How to close (kill) ssh ControlMaster connections manually

From the manual:

-O ctl_cmd
Control an active connection multiplexing master process. When the -O option is specified, the ctl_cmd argument is interpreted and passed to the master process. Valid commands are: check (check that the master process is running), forward (request forwardings without command execution), cancel (cancel forwardings), exit (request the master to exit), and stop (request the master to stop accepting further multiplexing requests).

Older versions only have check and exit, but that's enough for your purpose.

ssh -O check host.example.com

If you want to delete all connections (not just the connection to a particular host) in one fell swoop, then fuser /tmp/ssh_mux_* or lsof /tmp/ssh_mux_* will list the ssh clients that are controlling each socket. Use fuser -HUP -k tmp/ssh_mux_* to kill them all cleanly (using SIGHUP as the signal is best as it lets the clients properly remove their socket).


I wrote an open source utility, cmc, to manage ControlMaster sessions: ClockworkNet/cmc:

Usage:  cmc [ -c HOST | -o HOST | -x HOST ]
        cmc [ -L | -l | -O | -X ]
        cmc -h

ControlMaster Controller - Eases management of SSH ControlMaster connections

Options:
    -h      show this help message and exit
    -c HOST check HOST ControlMaster connection status (maybe specified more
            than once)
    -L      list ControlMasters defined in SSH_CONFIG
    -l      list ControlMaster connection sockets in ~/.ssh/ and check their
            connection status
    -O      open all ControlMasters defined in SSH_CONFIG
    -o HOST open a ControlMaster session (maybe specified more than once)
    -x HOST close ControlMaster session (maybe specified more than once)
    -X      exit all ControlMaster connections with sockets in ~/.ssh/

Notes:
    * Any unopened sockets in ~/.ssh/ are removed with -l and -X

This works for me using just the socket file for the control master:

$ ssh -o ControlPath=~/.ssh/<controlfile> -O check <bogus arg>

Example

Here's an example where I've already established a connection to a remote server:

$ ssh -o ControlPath=~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check blah
Master running (pid=89228)
$

And with it disconnected:

$ ssh -o ControlPath=~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O check blah
Control socket connect(/Users/user1/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74): No such file or directory
$

If it were still connected, this would force it to exit immediately:

$ ssh -o ControlPath=~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O exit blah
Exit request sent.
$

It's unclear to me, but it would appear to potentially be a bug in ssh that it requires an additional argument at the end, even though blah is meaningless in the context of the switches I'm using.

Without it gives me this:

$ ssh -o ControlPath=~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check
usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
           [-D [bind_address:]port] [-E log_file] [-e escape_char]
           [-F configfile] [-I pkcs11] [-i identity_file]
           [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]
           [-O ctl_cmd] [-o option] [-p port]
           [-Q cipher | cipher-auth | mac | kex | key]
           [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] [user@]hostname [command]

Version info

OSX
$ ssh -V
OpenSSH_6.9p1, LibreSSL 2.1.8
CentOS 7.x
$ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

I confirmed that on both of these versions, the need for the additional bogus argument was required.

References

  • How to tell if an ssh ControlMaster connection is in use
  • How to exit OpenSSH control master process without using lsof or fuser?