diff --git a/docs/man/borg.1 b/docs/man/borg.1
index 5e89a2eb..24dae7d1 100644
--- a/docs/man/borg.1
+++ b/docs/man/borg.1
@@ -434,6 +434,7 @@ When set, use the given filename as \fI\%INI\fP\-style logging configuration.
 .B BORG_RSH
 When set, use this command instead of \fBssh\fP\&. This can be used to specify ssh options, such as
 a custom identity file \fBssh \-i /path/to/private/key\fP\&. See \fBman ssh\fP for other options.
+Using the \fB\-\-rsh CMD\fP commandline option overrides the environment variable.
 .TP
 .B BORG_REMOTE_PATH
 When set, use the given path as borg executable on the remote (defaults to "borg" if unset).
diff --git a/docs/usage_general.rst.inc b/docs/usage_general.rst.inc
index 9ab1f593..d2d7d5c2 100644
--- a/docs/usage_general.rst.inc
+++ b/docs/usage_general.rst.inc
@@ -204,7 +204,8 @@ General:
         When set, use the given filename as INI_-style logging configuration.
     BORG_RSH
         When set, use this command instead of ``ssh``. This can be used to specify ssh options, such as
-        a custom identity file ``ssh -i /path/to/private/key``. See ``man ssh`` for other options.
+        a custom identity file ``ssh -i /path/to/private/key``. See ``man ssh`` for other options. Using
+        the ``--rsh CMD`` commandline option overrides the environment variable.
     BORG_REMOTE_PATH
         When set, use the given path as borg executable on the remote (defaults to "borg" if unset).
         Using ``--remote-path PATH`` commandline option overrides the environment variable.
diff --git a/src/borg/archiver.py b/src/borg/archiver.py
index 838d2876..58ba0569 100644
--- a/src/borg/archiver.py
+++ b/src/borg/archiver.py
@@ -2664,6 +2664,8 @@ def define_common_options(add_common_option):
             add_common_option('--debug-profile', metavar='FILE', dest='debug_profile', default=None,
                               help='Write execution profile in Borg format into FILE. For local use a Python-'
                                    'compatible file can be generated by suffixing FILE with ".pyprof".')
+            add_common_option('--rsh', metavar='RSH', dest='rsh',
+                              help="Use this command to connect to the 'borg serve' process (default: 'ssh')")
 
         def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False):
             add_option('-e', '--exclude', metavar='PATTERN', dest='patterns',
diff --git a/src/borg/remote.py b/src/borg/remote.py
index 54fdf574..83f3e03f 100644
--- a/src/borg/remote.py
+++ b/src/borg/remote.py
@@ -546,6 +546,7 @@ def __init__(self, location, create=False, exclusive=False, lock_wait=None, lock
         self.unpacker = get_limited_unpacker('client')
         self.server_version = parse_version('1.0.8')  # fallback version if server is too old to send version information
         self.p = None
+        self._args = args
         testing = location.host == '__testsuite__'
         # when testing, we invoke and talk to a borg process directly (no ssh).
         # when not testing, we invoke the system-installed ssh binary to talk to a remote borg.
@@ -691,7 +692,8 @@ def borg_cmd(self, args, testing):
 
     def ssh_cmd(self, location):
         """return a ssh command line that can be prefixed to a borg command line"""
-        args = shlex.split(os.environ.get('BORG_RSH', 'ssh'))
+        rsh = self._args.rsh or os.environ.get('BORG_RSH', 'ssh')
+        args = shlex.split(rsh)
         if location.port:
             args += ['-p', str(location.port)]
         if location.user:

Add --rsh option for setting BORG_RSH from the command line
diff --git a/src/borg/testsuite/repository.py b/src/borg/testsuite/repository.py
index 49f2e1f1..c6b53df6 100644
--- a/src/borg/testsuite/repository.py
+++ b/src/borg/testsuite/repository.py
@@ -798,6 +798,19 @@ def open(self, create=False):
         return RemoteRepository(Location('__testsuite__:' + os.path.join(self.tmppath, 'repository')),
                                 exclusive=True, create=create)
 
+    def _get_mock_args(self):
+        class MockArgs:
+            remote_path = 'borg'
+            umask = 0o077
+            debug_topics = []
+            rsh = None
+
+            def __contains__(self, item):
+                # To behave like argparse.Namespace
+                return hasattr(self, item)
+
+        return MockArgs()
+
     def test_invalid_rpc(self):
         self.assert_raises(InvalidRPCMethod, lambda: self.repository.call('__init__', {}))
 
@@ -856,6 +869,8 @@ def test_rpc_exception_transport(self):
             assert len(e.exception_full) > 0
 
     def test_ssh_cmd(self):
+        args = self._get_mock_args()
+        self.repository._args = args
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('ssh://example.com/foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('ssh://user@example.com/foo')) == ['ssh', 'user@example.com']
@@ -864,17 +879,8 @@ def test_ssh_cmd(self):
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '--foo', 'example.com']
 
     def test_borg_cmd(self):
-        class MockArgs:
-            remote_path = 'borg'
-            umask = 0o077
-            debug_topics = []
-
-            def __contains__(self, item):
-                # To behave like argparse.Namespace
-                return hasattr(self, item)
-
         assert self.repository.borg_cmd(None, testing=True) == [sys.executable, '-m', 'borg.archiver', 'serve']
-        args = MockArgs()
+        args = self._get_mock_args()
         # XXX without next line we get spurious test fails when using pytest-xdist, root cause unknown:
         logging.getLogger().setLevel(logging.INFO)
         # note: test logger is on info log level, so --info gets added automagically
@@ -884,12 +890,15 @@ def __contains__(self, item):
         args.debug_topics = ['something_client_side', 'repository_compaction']
         assert self.repository.borg_cmd(args, testing=False) == ['borg-0.28.2', 'serve', '--umask=077', '--info',
                                                                  '--debug-topic=borg.debug.repository_compaction']
-        args = MockArgs()
+        args = self._get_mock_args()
         args.storage_quota = 0
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info']
         args.storage_quota = 314159265
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info',
                                                                  '--storage-quota=314159265']
+        args.rsh = 'ssh -i foo'
+        self.repository._args = args
+        assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '-i', 'foo', 'example.com']
 
 
 class RemoteLegacyFree(RepositoryTestCaseBase):

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-xdist pytest-cov
apt-get update apt-get install -y gcc libacl1-dev libacl1 libssl-dev liblz4-dev libzstd-dev build-essential pkg-config python3-pkgconfig
3.9
requirements.d/development.txt requirements.d/docs.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
-e git+https://github.com/borgbackup/borg.git@1471fc0b0368a7ea3a973b0480f0ffb7451ab107#egg=borgbackup
cachetools==5.5.2
certifi==2025.1.31
chardet==5.2.0
charset-normalizer==3.4.1
colorama==0.4.6
coverage==7.8.0
Cython==3.0.12
distlib==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
execnet==2.1.1
filelock==3.18.0
guzzle_sphinx_theme==0.7.11
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
msgpack-python==0.5.6
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
py-cpuinfo==9.0.0
Pygments==2.19.1
pyproject-api==1.9.0
pytest==8.3.5
pytest-benchmark==5.1.0
pytest-cov==6.0.0
pytest-xdist==3.6.1
requests==2.32.3
setuptools-scm==8.2.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
tox==4.25.0
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
zipp==3.21.0

name: borg
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - colorama==0.4.6
      - coverage==7.8.0
      - cython==3.0.12
      - distlib==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - filelock==3.18.0
      - guzzle-sphinx-theme==0.7.11
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - msgpack-python==0.5.6
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - py-cpuinfo==9.0.0
      - pygments==2.19.1
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-benchmark==5.1.0
      - pytest-cov==6.0.0
      - pytest-xdist==3.6.1
      - requests==2.32.3
      - setuptools-scm==8.2.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tox==4.25.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - zipp==3.21.0
prefix: /opt/conda/envs/borg

src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_borg_cmd
src/borg/testsuite/repository.py::RepositoryTestCase::test1 src/borg/testsuite/repository.py::RepositoryTestCase::test2 src/borg/testsuite/repository.py::RepositoryTestCase::test_consistency src/borg/testsuite/repository.py::RepositoryTestCase::test_consistency2 src/borg/testsuite/repository.py::RepositoryTestCase::test_list src/borg/testsuite/repository.py::RepositoryTestCase::test_max_data_size src/borg/testsuite/repository.py::RepositoryTestCase::test_overwrite_in_same_transaction src/borg/testsuite/repository.py::RepositoryTestCase::test_scan src/borg/testsuite/repository.py::RepositoryTestCase::test_single_kind_transactions src/borg/testsuite/repository.py::LocalRepositoryTestCase::test_sparse1 src/borg/testsuite/repository.py::LocalRepositoryTestCase::test_sparse2 src/borg/testsuite/repository.py::LocalRepositoryTestCase::test_sparse_delete src/borg/testsuite/repository.py::LocalRepositoryTestCase::test_uncommitted_garbage src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_crash_before_compact_segments src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_crash_before_deleting_compacted_segments src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_crash_before_write_index src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_ignores_commit_tag_in_data src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_moved_deletes_are_tracked src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_replay_lock_upgrade src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_replay_lock_upgrade_old src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_replay_of_missing_index src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_shadow_index_rollback src/borg/testsuite/repository.py::RepositoryCommitTestCase::test_shadowed_entries_are_preserved src/borg/testsuite/repository.py::RepositoryAppendOnlyTestCase::test_append_only src/borg/testsuite/repository.py::RepositoryAppendOnlyTestCase::test_destroy_append_only src/borg/testsuite/repository.py::RepositoryFreeSpaceTestCase::test_additional_free_space src/borg/testsuite/repository.py::RepositoryFreeSpaceTestCase::test_create_free_space src/borg/testsuite/repository.py::QuotaTestCase::test_exceed_quota src/borg/testsuite/repository.py::QuotaTestCase::test_tracking src/borg/testsuite/repository.py::NonceReservation::test_commit_nonce_reservation src/borg/testsuite/repository.py::NonceReservation::test_commit_nonce_reservation_asserts src/borg/testsuite/repository.py::NonceReservation::test_get_free_nonce src/borg/testsuite/repository.py::NonceReservation::test_get_free_nonce_asserts src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_corrupted_hints src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_deleted_hints src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_deleted_index src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_index src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_index_corrupted src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_index_corrupted_without_integrity src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_index_outside_transaction src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_subtly_corrupted_hints src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_subtly_corrupted_hints_without_integrity src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_unknown_integrity_version src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_unreadable_hints src/borg/testsuite/repository.py::RepositoryAuxiliaryCorruptionTestCase::test_unreadable_index src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_crash_before_compact src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_corrupted_commit_segment src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_corrupted_segment src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_index_too_new src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_missing_commit_segment src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_missing_index src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_missing_segment src/borg/testsuite/repository.py::RepositoryCheckTestCase::test_repair_no_commits src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test1 src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test2 src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_consistency src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_consistency2 src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_invalid_rpc src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_list src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_max_data_size src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_overwrite_in_same_transaction src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_rpc_exception_transport src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_scan src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_single_kind_transactions src/borg/testsuite/repository.py::RemoteRepositoryTestCase::test_ssh_cmd src/borg/testsuite/repository.py::RemoteLegacyFree::test_legacy_free src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_crash_before_compact src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_corrupted_commit_segment src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_corrupted_segment src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_index_too_new src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_missing_commit_segment src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_missing_index src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_missing_segment src/borg/testsuite/repository.py::RemoteRepositoryCheckTestCase::test_repair_no_commits src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_info_to_correct_local_child src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_post11_format_messages src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_pre11_format_messages src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_remote_messages_screened src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_stderr_messages src/borg/testsuite/repository.py::RemoteLoggerTestCase::test_stderr_progress_messages
src/borg/archiver.py src/borg/remote.py docs/usage_general.rst.inc docs/man/borg.1
src/borg/archiver.py src/borg/remote.py docs/usage_general.rst.inc docs/man/borg.1