| Tested on | RHEL 10.2 (Coughlan) — vm2.lab.example (192.168.56.220) as client to vm1.lab.example (192.168.56.116) |
|---|---|
| Package | openssh-clients 9.9p1-25.el10_2 |
| Applies to | RHEL, Rocky Linux, AlmaLinux, Fedora, Ubuntu, Debian, and other Linux hosts with OpenSSH client support for connection sharing |
| Privilege | SSH login to the remote host; write access to ~/.ssh/config and the control socket directory on the client |
| Scope | Client-side ControlMaster, ControlPath, ControlPersist, verification with ssh -O, scp over a shared master, and closing the master. Does not cover ssh-agent setup, jump hosts, or server hardening beyond default session limits. |
| Related guides | ssh command Copy folder over SSH scp command OpenSSH authentication methods Test SSH connection |
Every new ssh session normally pays for TCP setup, key exchange, and authentication. SSH multiplexing skips that overhead on repeat visits: the first connection becomes a master, later ssh, scp, and sftp clients talk to it through a local control socket. SSH multiplexing is client-side — configure it on whichever host initiates the SSH, SCP, or SFTP connections. This walkthrough uses vm2.lab.example as the client and vm1.lab.example as the server.
What to configure on the client and server
Multiplexing is a client feature. The remote server does not have an "enable multiplexing" switch; it accepts one TCP connection and carries multiple channels the way SSH always has.
| Where | What you do | Files or commands |
|---|---|---|
Client (machine that runs ssh, scp, or sftp) |
Enable sharing, set the control socket path, open and close the master | ~/.ssh/config, ~/.ssh/sockets/, ssh, scp, ssh -O check, ssh -O exit |
| Server (remote host you log into) | Nothing required for multiplexing to work | Normal sshd service and your usual SSH login |
| Server (optional) | Raise per-connection session limits only if you hit them | /etc/ssh/sshd_config → MaxSessions, then reload sshd |
Every procedural section below states whether you run it on the client or server. Unless noted, commands run on vm2.lab.example toward vm1.lab.example.
What SSH multiplexing does
OpenSSH connection sharing works entirely on the client. You point several tools at the same control socket path; they ride one encrypted TCP link to the server as separate channels.
The flow looks like this:
Client A (ssh master) ──creates──► control socket ──► one TCP connection ──► sshd
Client B (ssh/scp) ──reuses───► control socket ──► same TCP ──► sshdThe server does not need a multiplexing toggle. It accepts one connection and multiplexes channels the way SSH always has; the client decides whether to open a fresh TCP session or attach to an existing master.
Three client options matter most:
| Option | Typical value | What it controls |
|---|---|---|
ControlMaster |
auto |
First client opens the master; later clients reuse it when the socket exists |
ControlPath |
~/.ssh/sockets/%r@%h-%p |
Filesystem path to the control socket; must be unique per user, host, and port |
ControlPersist |
120 (seconds) |
Keeps the master alive after the last session closes so the next client can attach without re-authenticating |
Placeholders in ControlPath keep socket names unique when you connect to the same host as different users or on non-default ports:
%r— remote username%h— target hostname%p— target port%C— hash of%l,%h,%p, and%r(handy when paths must stay short)
Configure multiplexing in ~/.ssh/config (client)
On the client (vm2.lab.example in this lab), scope multiplexing to one remote host so the rest of your SSH targets stay unchanged. Edit ~/.ssh/config on the machine that initiates connections:
Host lab-server
HostName 192.168.56.116
User root
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 120ControlMaster auto creates a master on the first ssh lab-server and reuses it afterward. ControlPersist 120 leaves the master up for two minutes after the last multiplexed session exits, which is long enough for a burst of scp copies without keeping the socket open all day.
You can pass the same options on the command line with -o ControlMaster=auto when a script should not depend on ~/.ssh/config.
Create the control socket directory (client)
On the client, OpenSSH does not create the directory in ControlPath for you. The socket file must live somewhere only your user can write:
mkdir -p ~/.ssh/socketsSet the directory mode so other users cannot reach your sockets:
chmod 700 ~/.ssh/socketsA mode of 700 on ~/.ssh/sockets matches what OpenSSH expects for private control state.
Open the first connection (client)
On the client, the first ssh to lab-server establishes the master connection and places a socket file under ~/.ssh/sockets/:
ssh lab-server hostnameSample output:
vm1.lab.exampleThat hostname confirms the session reached vm1.lab.example. The first hop always performs the full handshake; later hops attach through the socket you create here.
Verify the control socket (client)
Still on the client, list the socket directory to confirm OpenSSH created a control socket for this user, host, and port:
ls -la ~/.ssh/sockets/Sample output:
total 0
drwx------. 2 root root 36 Aug 21 13:15 .
drwx------. 3 root root 117 Aug 21 13:13 ..
srw-------. 1 root root 0 Aug 21 13:15 root@192.168.56.116-22The s at the start of the mode column marks a socket file. The name root@192.168.56.116-22 comes from %r@%h-%p in ControlPath.
Ask OpenSSH whether a master is still running for this host block:
ssh -O check lab-serverSample output:
Master running (pid=12624)The PID belongs to the background master process. While that line appears, new clients can multiplex without repeating authentication.
Reuse the master for another SSH session (client)
From the client, open a second session to the same host. With verbose logging, OpenSSH reports that it found an existing master:
ssh -vv lab-server 'uptime -s'Sample output (trimmed):
debug1: auto-mux: Trying existing master at '/root/.ssh/sockets/root@192.168.56.116-22'
debug1: mux_client_request_session: master session id: 2
2026-08-21 11:14:34The auto-mux line is the signal that multiplexing worked. The remote command output (uptime -s here) still prints normally after the debug lines when you use -vv.
On a slow link or when authentication involves a hardware token, the time saved is mostly skipped handshakes rather than microseconds on a LAN. The bigger win is fewer password or MFA prompts during a deployment script.
Copy files over the shared connection (client)
On the client, scp honors the same ControlPath as ssh when both use the same Host block. With a master already running from the steps above, run verbose scp so OpenSSH prints whether it attached to that master:
scp -v /etc/hosts lab-server:/tmp/hosts-copySample output (trimmed):
debug1: auto-mux: Trying existing master at '/root/.ssh/sockets/root@192.168.56.116-22'
debug1: mux_client_request_session: master session id: 2
scp: debug1: truncating at 415The auto-mux line is the proof that scp reused the existing connection. A successful copy alone only shows that the transfer worked; verbose multiplexing output shows it did not open a second TCP session.
Multiplex from the command line (client, no config file)
On the client, automation sometimes needs a dedicated socket outside ~/.ssh/config. Pick a path under your private socket directory, start a background master, then point later commands at it with -S:
ssh -fN -M -S ~/.ssh/sockets/manual-mux.sock root@192.168.56.116The flags mean:
-M— master mode for connection sharing-fN— go to background without running a remote command-S— control socket path (same asControlPath)
Confirm the socket exists:
ls -la ~/.ssh/sockets/manual-mux.sockSample output:
srw-------. 1 root root 0 Aug 21 13:22 /root/.ssh/sockets/manual-mux.sockRun a command through that socket:
ssh -S ~/.ssh/sockets/manual-mux.sock root@192.168.56.116 hostnameSample output:
vm1.lab.exampleClose the master and remove the socket when the script finishes:
ssh -O exit -S ~/.ssh/sockets/manual-mux.sock root@192.168.56.116Sample output:
Exit request sent.After exit, the socket file disappears:
ls ~/.ssh/sockets/manual-mux.sockSample output:
ls: cannot access '/root/.ssh/sockets/manual-mux.sock': No such file or directoryClose the master from ~/.ssh/config (client)
On the client, send an explicit exit request when you finish a work block and do not want ControlPersist to keep the master alive:
ssh -O exit lab-serverSample output:
Exit request sent.The control socket under ~/.ssh/sockets/ is removed and the TCP connection to the server closes. The next ssh lab-server performs a full login again.
If you only close an interactive shell but leave other multiplexed sessions open, the master stays up until the last channel closes (or until ControlPersist expires).
Server session limits (server, usually unchanged)
On the server (vm1.lab.example), multiplexing needs no sshd toggle, but each multiplexed channel still counts against per-connection limits. From the client, query those limits over SSH:
ssh lab-server 'sshd -T | grep maxsessions'If you are already logged into the server, the same check is sshd -T | grep maxsessions in that shell.
Sample output:
maxsessions 10Each multiplexed shell or subsystem session consumes a session channel on the existing TCP connection. The default MaxSessions 10 is normally sufficient; change it only if you actually hit that limit. Edit /etc/ssh/sshd_config on the server and reload sshd when you need more channels on one link.
You do not enable multiplexing in sshd_config; the daemon already multiplexes channels on any SSH connection.
Security notes (client)
On the client, the control socket is as sensitive as an authenticated session. Treat it like a private key file:
- Keep
ControlPathinside~/.ssh/(mode700) or another directory only your user owns. - Prefer
%Cor%r@%h-%pso socket names do not collide between hosts. - Set
ControlPersistto a finite value instead ofyeson laptops and shared machines. - Run
ssh -O exitbefore walking away from an unlocked console.
Multiplexing does not replace strong SSH authentication. Public key auth with a passphrase-protected key remains the baseline; multiplexing only avoids repeating that work within the persist window.
Troubleshooting
| Symptom | Likely cause | Fix (where) |
|---|---|---|
Control socket connect(...): No such file or directory |
No master running, or wrong ControlPath |
Client: run a first ssh with ControlMaster auto, or match the -S path the master used |
Too many open sessions on the server |
More channels than MaxSessions on one TCP link |
Server: raise MaxSessions in sshd_config and reload sshd; client: close unused sessions |
Second ssh still prompts for a password |
Different ControlPath, user, host, or port than the master |
Client: align %r, %h, and %p placeholders; connect with the same Host block |
Permission denied on the socket file |
ControlPath directory writable by other users |
Client: chmod 700 on the directory; never place sockets in /tmp on multi-user systems |
| Master never dies | ControlPersist yes or a long timeout |
Client: use a numeric timeout, or ssh -O exit when done |
auto-mux never appears in -vv output |
Multiplexing disabled or ControlMaster no |
Client: set ControlMaster auto in config or -o ControlMaster=auto on the command line |
References
Summary
SSH multiplexing keeps one authenticated TCP connection open on the client and lets later ssh, scp, and sftp sessions attach through a control socket. You enable it on the initiating host with ControlMaster, point clients at a unique ControlPath, and optionally keep the master alive with ControlPersist between bursts of work. The server needs no multiplexing setup beyond normal sshd. On the lab hosts, the client ssh lab-server created root@192.168.56.116-22 under ~/.ssh/sockets/, ssh -O check reported a running master, and scp -v showed auto-mux attaching to that same master.
The detail that trips people up is socket matching: the user, hostname, port, and ControlPath pattern must match exactly between the master and every multiplexed client. A typo in HostName or a socket path in a world-writable directory silently forces a fresh login. When you finish, ssh -O exit tears down the master so the next connection performs a full authentication cycle, which matters on shared workstations even when ControlPersist would eventually time out on its own.
For day-to-day use, a per-host block in ~/.ssh/config is enough. Reserve explicit -M and -S flags for scripts that need an isolated socket path under ~/.ssh/sockets/. Server-side changes are rare unless you stack many channels on one link and hit MaxSessions.

