diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -69,6 +69,7 @@ from . import (
 )
 from .utils import (
     dateutil,
+    procutil,
     stringutil,
     urlutil,
 )
@@ -6672,7 +6673,25 @@ def serve(ui, repo, **opts):
             raise error.RepoError(
                 _(b"there is no Mercurial repository here (.hg not found)")
             )
-        s = wireprotoserver.sshserver(ui, repo)
+        accesshidden = False
+        if repo.filtername is None:
+            allow = ui.configlist(
+                b'experimental', b'server.allow-hidden-access'
+            )
+            user = procutil.getuser()
+            if allow and scmutil.ismember(ui, user, allow):
+                accesshidden = True
+            else:
+                msg = (
+                    _(
+                        b'ignoring request to access hidden changeset by '
+                        b'unauthorized user: %s\n'
+                    )
+                    % user
+                )
+                ui.warn(msg)
+
+        s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
         s.serve_forever()
         return
 
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -177,7 +177,9 @@ def _cleanuppipes(ui, pipei, pipeo, pipe
         ui.develwarn(b'missing close on SSH connection created at:\n%s' % warn)
 
 
-def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
+def _makeconnection(
+    ui, sshcmd, args, remotecmd, path, sshenv=None, remotehidden=False
+):
     """Create an SSH connection to a server.
 
     Returns a tuple of (process, stdin, stdout, stderr) for the
@@ -187,8 +189,12 @@ def _makeconnection(ui, sshcmd, args, re
         sshcmd,
         args,
         procutil.shellquote(
-            b'%s -R %s serve --stdio'
-            % (_serverquote(remotecmd), _serverquote(path))
+            b'%s -R %s serve --stdio%s'
+            % (
+                _serverquote(remotecmd),
+                _serverquote(path),
+                b' --hidden' if remotehidden else b'',
+            )
         ),
     )
 
@@ -393,13 +399,6 @@ class sshv1peer(wireprotov1peer.wirepeer
         stderr and to forward its output.
         """
         super().__init__(ui, path=path, remotehidden=remotehidden)
-        if remotehidden:
-            msg = _(
-                b"ignoring `--remote-hidden` request\n"
-                b"(access to hidden changeset for ssh peers not supported "
-                b"yet)\n"
-            )
-            ui.warn(msg)
         # self._subprocess is unused. Keeping a handle on the process
         # holds a reference and prevents it from being garbage collected.
         self._subprocess = proc
@@ -416,6 +415,7 @@ class sshv1peer(wireprotov1peer.wirepeer
         self._caps = caps
         self._autoreadstderr = autoreadstderr
         self._initstack = b''.join(util.getstackframes(1))
+        self._remotehidden = remotehidden
 
     # Commands that have a "framed" response where the first line of the
     # response contains the length of that response.
@@ -683,7 +683,13 @@ def make_peer(
             raise error.RepoError(_(b'could not create remote repo'))
 
     proc, stdin, stdout, stderr = _makeconnection(
-        ui, sshcmd, args, remotecmd, remotepath, sshenv
+        ui,
+        sshcmd,
+        args,
+        remotecmd,
+        remotepath,
+        sshenv,
+        remotehidden=remotehidden,
     )
 
     peer = _make_peer(
diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -446,7 +446,7 @@ class sshv1protocolhandler:
         pass
 
 
-def _runsshserver(ui, repo, fin, fout, ev):
+def _runsshserver(ui, repo, fin, fout, ev, accesshidden=False):
     # This function operates like a state machine of sorts. The following
     # states are defined:
     #
@@ -487,7 +487,9 @@ def _runsshserver(ui, repo, fin, fout, e
                 _sshv1respondbytes(fout, b'')
                 continue
 
-            rsp = wireprotov1server.dispatch(repo, proto, request)
+            rsp = wireprotov1server.dispatch(
+                repo, proto, request, accesshidden=accesshidden
+            )
             repo.ui.fout.flush()
             repo.ui.ferr.flush()
 
@@ -522,10 +524,11 @@ def _runsshserver(ui, repo, fin, fout, e
 
 
 class sshserver:
-    def __init__(self, ui, repo, logfh=None):
+    def __init__(self, ui, repo, logfh=None, accesshidden=False):
         self._ui = ui
         self._repo = repo
         self._fin, self._fout = ui.protectfinout()
+        self._accesshidden = accesshidden
 
         # Log write I/O to stdout and stderr if configured.
         if logfh:
@@ -542,4 +545,6 @@ class sshserver:
 
     def serveuntil(self, ev):
         """Serve until a threading.Event is set."""
-        _runsshserver(self._ui, self._repo, self._fin, self._fout, ev)
+        _runsshserver(
+            self._ui, self._repo, self._fin, self._fout, ev, self._accesshidden
+        )
diff --git a/tests/test-remote-hidden.t b/tests/test-remote-hidden.t
--- a/tests/test-remote-hidden.t
+++ b/tests/test-remote-hidden.t
@@ -6,6 +6,8 @@ Test the ability to access a hidden revi
 
   $ . $TESTDIR/testlib/obsmarker-common.sh
   $ cat >> $HGRCPATH << EOF
+  > [ui]
+  > ssh = "$PYTHON" "$RUNTESTDIR/dummyssh"
   > [phases]
   > # public changeset are not obsolete
   > publish=false
@@ -305,6 +307,98 @@ pulling an hidden changeset with --remot
   abort: filtered revision 'be215fbb8c50' (not in 'served' subset)
   [255]
 
+Test --remote-hidden for ssh peer
+----------------------------------
+
+  $ hg clone --pull ssh://user@dummy/repo-with-hidden client-ssh
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  2 new obsolescence markers
+  new changesets 5f354f46e585:c33affeb3f6b (1 drafts)
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg -R client-ssh log -G --hidden -v
+  @  1:c33affeb3f6b c_Amend_New [draft]
+  |
+  o  0:5f354f46e585 c_Public [public]
+  
+
+Check on a server that do not allow hidden access:
+``````````````````````````````````````````````````
+
+pulling an hidden changeset should fail:
+
+  $ hg -R client-ssh pull -r be215fbb8c50
+  pulling from ssh://user@dummy/repo-with-hidden
+  abort: filtered revision 'be215fbb8c50' (not in 'served' subset)
+  [255]
+
+pulling an hidden changeset with --remote-hidden should succeed:
+
+  $ hg -R client-ssh pull --remote-hidden -r be215fbb8c50
+  pulling from ssh://user@dummy/repo-with-hidden
+  remote: ignoring request to access hidden changeset by unauthorized user: * (glob)
+  abort: filtered revision 'be215fbb8c50' (not in 'served' subset)
+  [255]
+  $ hg -R client-ssh log -G --hidden -v
+  @  1:c33affeb3f6b c_Amend_New [draft]
+  |
+  o  0:5f354f46e585 c_Public [public]
+  
+
+Check on a server that do allow hidden access:
+``````````````````````````````````````````````
+
+  $ cat << EOF >> repo-with-hidden/.hg/hgrc
+  > [experimental]
+  > server.allow-hidden-access=*
+  > EOF
+
+pulling an hidden changeset should fail:
+
+  $ hg -R client-ssh pull -r be215fbb8c50
+  pulling from ssh://user@dummy/repo-with-hidden
+  abort: filtered revision 'be215fbb8c50' (not in 'served' subset)
+  [255]
+
+pulling an hidden changeset with --remote-hidden should succeed:
+
+  $ hg -R client-ssh pull --remote-hidden -r be215fbb8c50
+  pulling from ssh://user@dummy/repo-with-hidden
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  (1 other changesets obsolete on arrival)
+  (run 'hg heads' to see heads)
+  $ hg -R client-ssh log -G --hidden -v
+  x  2:be215fbb8c50 c_Amend_Old [draft]
+  |
+  | @  1:c33affeb3f6b c_Amend_New [draft]
+  |/
+  o  0:5f354f46e585 c_Public [public]
+  
+
+Pulling a secret changeset is still forbidden:
+
+secret visible:
+
+  $ hg -R client-ssh pull --remote-hidden -r 8d28cbe335f3
+  pulling from ssh://user@dummy/repo-with-hidden
+  abort: filtered revision '8d28cbe335f3' (not in 'served.hidden' subset)
+  [255]
+
+secret hidden:
+
+  $ hg -R client-ssh pull --remote-hidden -r 1c6afd79eb66
+  pulling from ssh://user@dummy/repo-with-hidden
+  abort: filtered revision '1c6afd79eb66' (not in 'served.hidden' subset)
+  [255]
+
 =============
 Final cleanup
 =============