01
Collect the timing and scope
Note whether disconnects follow a consistent idle duration, a laptop sleep event, a network switch, or server maintenance. Compare with a bounded test on another authorized host or network when possible. A repeatable pattern narrows the investigation but does not identify the cause by itself.
Review the client’s effective keepalive settings and the server logs around the disconnect. If the server intentionally ends idle sessions or a shell timeout is configured, adding client probes may not change that policy.
ssh -G app-server
ssh -v app-server02
Apply keepalives to the affected host
ServerAliveInterval asks the client to send an encrypted protocol-level check when it has not received data from the server. ServerAliveCountMax bounds unanswered checks before disconnection. These differ from relying solely on TCP keepalive behavior.
Start with one host entry and choose values that fit the network and server policy. Place the specific rule before broad defaults where needed, then inspect it with ssh -G. Avoid changing every destination just because one path has an idle problem.
Host app-server
HostName server.example.com
ServerAliveInterval 30
ServerAliveCountMax 303
Test healthy idleness and an unavailable peer separately
Our healthy lab connection remained open during a short idle command and returned its final marker. In a separate run, we paused only the disposable server after authentication. With one-second checks and a count of two, the client detected the unresponsive peer and exited.
That test establishes failure detection in a controlled case. It does not prove that a thirty-second interval will overcome a particular router’s timeout, or that all client disconnects share the same cause. Sleep and link loss can still interrupt the transport.
# Example of a short benign idle check on an authorized server:
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
app-server 'sleep 120; printf "idle check completed\n"'04
Do not confuse detection with recovery
A new SSH connection is a new transport. The keepalive options do not reattach its terminal, replay a command safely, or establish whether a partially completed operation succeeded. After a disconnect, check the remote result before retrying a state-changing command.
If long-running work must survive terminal loss, use a workflow designed for that requirement, such as an approved terminal multiplexer or service manager. Configure that deliberately rather than treating a longer timeout as job supervision.
05
Verify the original use case after the change
Repeat the ordinary idle pattern that used to fail, and compare the timing and logs. If disconnects continue at exactly a server-enforced deadline, investigate that policy with its owner. If they track laptop sleep or network changes, keepalive tuning may be the wrong lever.
Keep only the setting that the evidence supports. A faster error is useful when a connection is dead, but it is a different outcome from a connection that now stays usable. Record which outcome you actually observed.
Know the limits
Tested with OpenSSH 9.2p1 against a healthy idle server and a deliberately paused disposable server. We did not simulate a real NAT idle timer. The short one-second lab interval is for reproduction; the example configuration uses a less aggressive interval.
Sources & further reading
A technical publication by CoreTrailKit.
Browse all articles