Skip to content

SSH Connection Multiplexing (ControlMaster): Cutting the Wait When You Connect to the Same Server Repeatedly

If you run WP-CLI over SSH many times in a row, you may notice that much of the delay comes before the command even starts. Each call opens a new TCP connection, negotiates keys and authenticates from scratch.

OpenSSH can reuse an established connection through ControlMaster. This article explains what happens under the hood, how to configure it, and what to watch for, with timings measured against a real server.

Note: I measured from a Mac (OpenSSH 10.2) to a hosting server in Japan by running true repeatedly. Numbers depend on your network and server, so treat them as one example.

What each SSH call does

Every ssh host command runs these steps again:

  1. Open a TCP connection
  2. Negotiate ciphers and exchange keys
  3. Verify the server and authenticate with a public key
  4. Open a session and run the command

Only step 4 is the work you care about. Steps 1–3 repeat every time, and in a script that calls SSH dozens of times they make up most of the waiting.

The idea behind ControlMaster

The first connection stays alive as a “master”. Later ssh commands attach their sessions to it instead of connecting again.

  • The first ssh opens the connection and creates a control socket file locally
  • Later ssh commands talk to that socket and add a session to the existing connection
  • No new key exchange or authentication takes place

Configuration

Add this to ~/.ssh/config per host. The host, user and key path are placeholders.

Host myserver
    HostName example.com
    User deploy
    IdentityFile ~/.ssh/example_key
    ControlMaster auto
    ControlPath ~/.ssh/cm-%C
    ControlPersist 60
  • ControlMaster auto: become the master if no socket exists, otherwise attach to it
  • ControlPath: where the socket lives; %C is a hash of the connection details, so each host gets its own short path
  • ControlPersist 60: keep the master running in the background for 60 seconds after the last session ends

ControlPersist matters. Without it the master exits with the first session, and the next command opens a fresh connection again. Socket paths also have an OS-specific length limit, which %C helps you stay under.

Measured results

I ran true five times in a row against the same server (single measurement):

Condition Total for 5 runs
No multiplexing 2.64 s
Multiplexing (ControlPersist 30) 0.83 s

Only the first run actually opened a connection; the rest reused it.

For three runs of wp option get blogname:

Condition Total for 3 runs
No multiplexing 3.36 s
Multiplexing 2.64 s

The gap is smaller because WP-CLI spends its own time starting PHP and loading WordPress. Multiplexing only removes connection setup; it does not change how long the command itself takes. The benefit is most visible with many short commands.

Checking and stopping the master

ssh -O check myserver
ssh -O exit myserver

I stopped the master with -O exit after each measurement.

Things to watch

  • The socket file: whoever can use the socket can use that connection. Keep it in a directory only you can read and write, never a shared location.
  • Stale sockets: after an abnormal exit a leftover socket can make connections fail; delete it and reconnect.
  • Shared fate: if the master drops, the attached sessions drop with it. For long jobs or large transfers, a separate connection may be safer.
  • Keep ControlPersist short: tens of seconds to a few minutes is plenty.
  • After changing settings: a master started with old settings keeps them; stop it with -O exit before testing.

Summary

  • Every SSH call repeats TCP, key exchange and authentication.
  • ControlMaster reuses the first connection for later calls.
  • ControlMaster auto, ControlPath and ControlPersist in ~/.ssh/config are the core settings.
  • Measured: 2.64 s to 0.83 s for five short commands, with a smaller gain for heavier commands like WP-CLI.
  • Mind where the socket lives and what happens if the master drops.

If you manage several servers, first organize them as in Organizing hosts with ~/.ssh/config, then add multiplexing only to the hosts you connect to repeatedly.