SSH ControlMaster leaves a stale socket after a network drop and every deploy hangs on connect
SSH ControlMaster leaves a stale socket after a network drop and every deploy hangs on connect
A deploy starts, prints nothing after Connect to host, and sits there until the CI job timeout. Retries hit the same dead Unix socket under ~/.ssh. The network has already recovered; the mux path has not. An ssh controlmaster stale socket turns a short outage into a deploy queue full of hung jobs, and the fix is usually a single file removal—if you can identify it safely.
Why a network drop breaks multiplexing
ControlMaster keeps one SSH connection open and lets later ssh clients reuse its Unix domain socket instead of doing a full TCP and authentication handshake. When the network drops, the master process can remain behind with the socket file still present, while no live process is servicing it. New clients try the stale path first and wait or fail before falling back.
The effective settings come from your SSH config, commonly ControlMaster auto and ControlPath [link needed]. A literal shared path can collide across hosts; %C gives a hash of local host, remote host, port, and user [link needed]. Check the effective value before deleting anything.
Diagnose and clear an ssh controlmaster stale socket
1. Print the effective control path for the target:
```bash
ssh -G deploy@example-host | awk '/^controlpath /{print $2}'
```
If it prints none, multiplexing is not involved.
2. Check the master without opening a session:
```bash
ssh -O check deploy@example-host
```
A live master reports that it is running. A connection error against the path points to a stale socket [link needed].
3. Confirm no process is listening on that socket. ssh -O check is the primary test; ss -xlp | grep -- "$(basename "$path")" is a second check if available [link needed]. Do not delete a socket that a live master owns.
4. Remove only the ssh controlmaster stale socket file:
```bash
rm -f -- "$path"
```
5. Retry, bypassing mux once to confirm the host is reachable:
```bash
ssh -S none deploy@example-host true
```
Then run the normal deploy. The next connection recreates the socket.
If ssh -O exit deploy@example-host succeeds, it normally cleans up the socket as well. Use it first when the master still responds; use rm when it does not.
Prevent the next stale socket
Put multiplexing in a Host block, not a global literal path:
Host deploy-*
ControlMaster auto
ControlPath ~/.ssh/cm/%C
ControlPersist 5m
ServerAliveInterval 30
ServerAliveCountMax 3
Create ~/.ssh/cm with mode 700. ServerAliveInterval helps the client notice a dead peer, though it does not make every drop detectable [link needed]. In deploy wrappers, run ssh -O check as a preflight and clear the path only when the check fails and no listener exists. Keep a -S none fallback so a broken mux does not block the deploy entirely.
When NOT to do this
Do not add ControlMaster to a host you SSH into once per day; the stale-socket failure mode buys little. Do not delete a shared socket blindly on a multi-user box where another engineer may have a live master. And if your deploy timeout is shorter than your ControlPersist plus connection timeouts, measure the actual failure before tuning values.
Checklist
ssh -G hostshows aControlPathunder a dedicated directory.- The directory exists with mode
700. ControlPathincludes%C.ssh -O check hostruns before deploys.- A failed check leads to listener verification, then removal.
ssh -S none host trueworks as a fallback.- The ssh controlmaster stale socket is cleared and the deploy no longer hangs.