Every new SSH connection performs a TCP handshake, a key exchange and authentication. To a distant server that can take a second or more, and with 2FA it also means another prompt. SSH multiplexing opens one master connection and runs every later session to the same host through it. New shells, scp, rsync, git and Ansible tasks then start almost instantly.

Enable it in ~/.ssh/config

Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m
  • ControlMaster auto — use an existing master if there is one, otherwise become the master.
  • ControlPath — the socket file for the shared connection. %r is the user, %h the host and %p the port, so each destination gets its own socket.
  • ControlPersist 10m — keep the master open in the background for 10 minutes after the last session closes.

That’s all. The first ssh web1 connects normally. Every following ssh web1 within the persist window starts in milliseconds.

Long hostnames can exceed the Unix socket path limit (about 104 characters). Use a hash instead:

ControlPath ~/.ssh/cm-%C

%C is a hash of the connection details.

See the difference

time ssh web1 true      # first: ~0.5–2 s
time ssh web1 true      # second: ~0.02 s

Where it helps most:

  • Ansible: runs many SSH commands per host. Ansible enables ControlPersist by default (60 s), and a longer persist plus pipelining (pipelining = True in ansible.cfg) speeds up playbooks a lot. See Ansible playbooks.
  • rsync/scp loops in scripts.
  • Git over SSH to your own Git server.
  • 2FA-protected servers: authenticate once, then open more sessions without new codes (within the persist time).
  • Jump hosts: the hop to the bastion is reused. See ProxyJump.

Managing master connections

ssh -O check web1        # is a master running?
ssh -O exit web1         # close the master (and all sessions using it)
ssh -O stop web1         # stop accepting new sessions, keep existing ones
ls ~/.ssh/cm-*           # see sockets

Force a fresh, separate connection once (for testing new sshd settings, for example):

ssh -o ControlMaster=no -o ControlPath=none web1

That’s important when changing the server’s SSH config. With multiplexing, your “new” test connection may silently reuse the old master, and you won’t notice that new logins are broken. Always test changes with a non-multiplexed connection before closing your session.

Port forwards and multiplexing

Port forwards (-L, -R) requested on later sessions are added to the master connection. To add or cancel forwards on a running master:

ssh -O forward -L 5432:127.0.0.1:5432 db1
ssh -O cancel  -L 5432:127.0.0.1:5432 db1

Limiting it to certain hosts

Multiplexing is safe for most uses, but you may want it only for your servers:

Host web1 web2 db1 bastion
    ControlMaster auto
    ControlPath ~/.ssh/cm-%C
    ControlPersist 15m

Caveats

  • The master’s lifetime: if the master’s network connection drops, every multiplexed session drops with it. Combine with keepalives. See SSH keepalive.
  • Security: anyone who can access your control socket can open sessions on your existing connection without authenticating. Keep sockets in ~/.ssh (mode 700), never in shared directories like /tmp.
  • Server limits: MaxSessions in sshd_config (default 10) caps sessions per connection. Heavy parallel tools may need it raised, or will fall back to new connections.
  • Stale sockets after crashes: ssh -O exit host, or delete the socket file.
  • Windows OpenSSH: ControlMaster isn’t supported in the native Windows client. Use WSL or Git Bash’s OpenSSH.

Quick reference

Task Command / config
Enable ControlMaster auto + ControlPath ~/.ssh/cm-%C + ControlPersist 10m
Status ssh -O check host
Close master ssh -O exit host
Bypass once ssh -o ControlMaster=no -o ControlPath=none host
Add forward ssh -O forward -L 8080:localhost:80 host

Related: SSH config file and SSH agent forwarding.

  • SSH
  • Productivity
  • DevOps