diff --git a/mercurial/configitems.py b/mercurial/configitems.py
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_bWVyY3VyaWFsL2NvbmZpZ2l0ZW1zLnB5..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_bWVyY3VyaWFsL2NvbmZpZ2l0ZW1zLnB5 100644
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -995,6 +995,9 @@
 coreconfigitem('storage', 'revlog.zlib.level',
     default=None,
 )
+coreconfigitem('storage', 'revlog.zstd.level',
+    default=None,
+)
 coreconfigitem('server', 'bookmarks-pushkey-compat',
     default=True,
 )
diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_bWVyY3VyaWFsL2hlbHAvY29uZmlnLnR4dA==..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_bWVyY3VyaWFsL2hlbHAvY29uZmlnLnR4dA== 100644
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1886,6 +1886,12 @@
     Value range from 1 (lowest compression) to 9 (highest compression). Zlib
     default value is 6.
 
+
+``revlog.zstd.level``
+    zstd compression level used when storing data into the repository. Accepted
+    Value range from 1 (lowest compression) to 22 (highest compression).
+    (default 3)
+
 ``server``
 ----------
 
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_bWVyY3VyaWFsL2xvY2FscmVwby5weQ==..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_bWVyY3VyaWFsL2xvY2FscmVwby5weQ== 100644
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -802,6 +802,11 @@
         if not (0 <= options[b'zlib.level'] <= 9):
             msg = _('invalid value for `storage.revlog.zlib.level` config: %d')
             raise error.Abort(msg % options[b'zlib.level'])
+    options[b'zstd.level'] = ui.configint(b'storage', b'revlog.zstd.level')
+    if options[b'zstd.level'] is not None:
+        if not (0 <= options[b'zstd.level'] <= 22):
+            msg = _('invalid value for `storage.revlog.zstd.level` config: %d')
+            raise error.Abort(msg % options[b'zstd.level'])
 
     if repository.NARROW_REQUIREMENT in requirements:
         options[b'enableellipsis'] = True
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_bWVyY3VyaWFsL3JldmxvZy5weQ==..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_bWVyY3VyaWFsL3JldmxvZy5weQ== 100644
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -419,6 +419,8 @@
             self._compengine = opts['compengine']
         if 'zlib.level' in opts:
             self._compengineopts['zlib.level'] = opts['zlib.level']
+        if 'zstd.level' in opts:
+            self._compengineopts['zstd.level'] = opts['zstd.level']
         if 'maxdeltachainspan' in opts:
             self._maxdeltachainspan = opts['maxdeltachainspan']
         if self._mmaplargeindex and 'mmapindexthreshold' in opts:
diff --git a/mercurial/utils/compression.py b/mercurial/utils/compression.py
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_bWVyY3VyaWFsL3V0aWxzL2NvbXByZXNzaW9uLnB5..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_bWVyY3VyaWFsL3V0aWxzL2NvbXByZXNzaW9uLnB5 100644
--- a/mercurial/utils/compression.py
+++ b/mercurial/utils/compression.py
@@ -721,8 +721,12 @@
 
     def revlogcompressor(self, opts=None):
         opts = opts or {}
-        return self.zstdrevlogcompressor(self._module,
-                                         level=opts.get('level', 3))
+        level = opts.get('zstd.level')
+        if level is None:
+            level = opts.get('level')
+        if level is None:
+            level = 3
+        return self.zstdrevlogcompressor(self._module, level=level)
 
 compengines.register(_zstdengine())
 
diff --git a/tests/test-repo-compengines.t b/tests/test-repo-compengines.t
index 1fac9b931d4617f1ea6bc76a9c25fd3d4308ad29_dGVzdHMvdGVzdC1yZXBvLWNvbXBlbmdpbmVzLnQ=..bb271ec2fbfbd456d1281c5dad21f92db6d30f7b_dGVzdHMvdGVzdC1yZXBvLWNvbXBlbmdpbmVzLnQ= 100644
--- a/tests/test-repo-compengines.t
+++ b/tests/test-repo-compengines.t
@@ -138,3 +138,58 @@
   abort: invalid value for `storage.revlog.zlib.level` config: 42
   [255]
 
+checking zstd options
+=====================
+
+  $ hg init zstd-level-default --config experimental.format.compression=zstd
+  $ hg init zstd-level-1 --config experimental.format.compression=zstd
+  $ cat << EOF >> zstd-level-1/.hg/hgrc
+  > [storage]
+  > revlog.zstd.level=1
+  > EOF
+  $ hg init zstd-level-22 --config experimental.format.compression=zstd
+  $ cat << EOF >> zstd-level-22/.hg/hgrc
+  > [storage]
+  > revlog.zstd.level=22
+  > EOF
+
+
+  $ commitone() {
+  >    repo=$1
+  >    cp $RUNTESTDIR/bundles/issue4438-r1.hg $repo/a
+  >    hg -R $repo add $repo/a
+  >    hg -R $repo commit -m some-commit
+  > }
+
+  $ for repo in zstd-level-default zstd-level-1 zstd-level-22; do
+  >     commitone $repo
+  > done
+
+  $ $RUNTESTDIR/f -s zstd-*/.hg/store/data/*
+  zstd-level-1/.hg/store/data/a.i: size=4097
+  zstd-level-22/.hg/store/data/a.i: size=4091
+  zstd-level-default/.hg/store/data/a.i: size=4094
+
+Test error cases
+
+  $ hg init zstd-level-invalid --config experimental.format.compression=zstd
+  $ cat << EOF >> zstd-level-invalid/.hg/hgrc
+  > [storage]
+  > revlog.zstd.level=foobar
+  > EOF
+  $ commitone zstd-level-invalid
+  abort: storage.revlog.zstd.level is not a valid integer ('foobar')
+  abort: storage.revlog.zstd.level is not a valid integer ('foobar')
+  [255]
+
+  $ hg init zstd-level-out-of-range --config experimental.format.compression=zstd
+  $ cat << EOF >> zstd-level-out-of-range/.hg/hgrc
+  > [storage]
+  > revlog.zstd.level=42
+  > EOF
+
+  $ commitone zstd-level-out-of-range
+  abort: invalid value for `storage.revlog.zstd.level` config: 42
+  abort: invalid value for `storage.revlog.zstd.level` config: 42
+  [255]
+