SSH Broken Pipe Error: Causes and Fixes

By 

•

Published on

•

8 min read

Terminal surrounded by an interrupted SSH connection loop and keepalive pulses

You connect to a server, leave the terminal idle for a few minutes, and return to find the session frozen or closed with client_loop: send disconnect: Broken pipe. The login worked, but something between the client and server discarded the quiet connection, or the network disappeared long enough for SSH to give up.

A common cause is an idle timeout on a router, firewall, VPN, or NAT gateway. A Wi-Fi interruption or a server reboot can produce the same symptom. In this guide, we will explain how to configure SSH keepalives, find the cause of a disconnect, and protect long-running commands.

Quick Reference

For a printable quick reference, see the SSH cheatsheet .

TaskSetting or command
Test client keepalives oncessh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@example.com
Configure client keepalivesServerAliveInterval 60 and ServerAliveCountMax 3
Show the effective client settingsssh -G example.com | grep -i serveralive
Debug a disconnectssh -vvv user@example.com
Validate the server configurationsudo sshd -t
Read SSH server logs on Ubuntu or Debiansudo journalctl -u ssh.service -u ssh.socket -b
Keep a command alive after disconnectingRun it inside tmux

Test SSH Keepalives from the Client

Start with a one-time connection that sends a keepalive after 60 seconds without incoming data:

Terminal
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@example.com

ServerAliveInterval=60 tells the client to send a message through the encrypted SSH channel when it has received no data for 60 seconds. This exchange can prevent a router or firewall from dropping an idle connection. ServerAliveCountMax=3 sets the limit for unanswered requests, so an unresponsive server is detected after roughly three minutes instead of leaving the session hanging indefinitely.

Leave this test session idle longer than it would normally survive. If it remains connected, make the settings permanent on the client.

The interval must be shorter than the network device’s idle timeout. If the connection drops in less than a minute, try ServerAliveInterval=15 instead. With a count of 3, that also reduces the time allowed for an unresponsive connection to roughly 45 seconds.

Configure Keepalives in ~/.ssh/config

On your local machine, create the ~/.ssh directory if it does not exist, set its permissions, and open the SSH client configuration file:

Terminal
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/config

Add the settings to the host that drops connections. If you already have a block for that host, update it instead of adding a second one:

~/.ssh/configtxt
Host production
    HostName example.com
    User deploy
    ServerAliveInterval 60
    ServerAliveCountMax 3

You can then connect with the short host name:

Terminal
ssh production

The host-specific block is the safer starting point because it changes only the troublesome connection. If several networks and servers have the same problem, put the settings in a wildcard block at the bottom of the file:

~/.ssh/configtxt
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

OpenSSH uses the first value it finds for each setting. Put specific host blocks before Host * so the defaults do not override them.

Protect the file and inspect the values OpenSSH will use for a host:

Terminal
chmod 600 ~/.ssh/config
ssh -G production | grep -i serveralive

For the configuration above, the output should be:

output
serveralivecountmax 3
serveraliveinterval 60

The values confirm that keepalives are enabled at a 60-second interval with a limit of three unanswered requests. Our guide to the SSH config file covers host aliases, keys, ports, and precedence in more detail.

Check Why the Connection Closed

Keepalives can prevent idle network timeouts, but they cannot keep a session connected through a server reboot or a network outage. Run the client with verbose logging when the disconnect is repeatable:

Terminal
ssh -vvv user@example.com

Look at the last lines after the failure. Broken pipe means SSH could no longer write to the connection; it does not tell you what caused the failure.

Once keepalives are enabled, a connection that stops answering ends with a different message:

output
Timeout, server example.com not responding.

The client sent ServerAliveCountMax keepalives without receiving a reply, then closed the session. The keepalives worked; the network path or the server stopped answering. Compare the client messages with the server logs at the same timestamp.

On Ubuntu and Debian, inspect the current boot logs for both the service and socket units:

Terminal
sudo journalctl -u ssh.service -u ssh.socket -b

On Fedora, RHEL, and derivatives, use the sshd unit:

Terminal
sudo journalctl -u sshd.service -b

Use sudo journalctl -b to check the wider system log for an out-of-memory event or other failures around the same timestamp. A normal SSH configuration reload does not usually end established sessions. If every client disconnects at once, check the server and the network they share. If only one laptop drops when it changes Wi-Fi networks or reconnects to a VPN, check that laptop’s network connection first.

Configure Server-Side Keepalives

When you administer the server, you can configure it to send keepalives to quiet clients. These settings go on the remote server, not in your local ~/.ssh/config.

First, check whether /etc/ssh/sshd_config includes a directory for configuration snippets:

Terminal
sudo grep -nE '^[[:space:]]*Include[[:space:]]' /etc/ssh/sshd_config

On Ubuntu, the default configuration includes Include /etc/ssh/sshd_config.d/*.conf. If your server includes that path, open a drop-in file:

Terminal
sudo nano /etc/ssh/sshd_config.d/10-keepalive.conf

Add the following settings:

/etc/ssh/sshd_config.d/10-keepalive.conftxt
ClientAliveInterval 60
ClientAliveCountMax 3

If your configuration does not include this directory, edit the existing global settings in /etc/ssh/sshd_config instead, before any Match blocks. As with the client configuration, the first value obtained for most settings takes precedence.

ClientAliveInterval tells the server to request a response after receiving no data from the client for the specified interval. ClientAliveCountMax controls how many unanswered requests it permits before disconnecting the client. A healthy client answers automatically, even when you are not typing. These options do not impose a timeout for an idle user.

Validate the configuration before applying it:

Terminal
sudo sshd -t

No output means the configuration passed the check. If an error appears, correct it before reloading SSH. Then inspect the effective keepalive settings:

Terminal
sudo sshd -T | grep -E '^clientalive(interval|countmax) '

The output should show clientaliveinterval 60 and clientalivecountmax 3. If the values differ, check for an earlier setting or a drop-in file that is not being included.

If the server uses Match rules, plain sshd -T does not show the settings for a particular login. Use sudo sshd -T -C user=deploy,addr=198.51.100.10,host=client.example.com, replacing the examples with the remote username and the client’s source address and hostname as seen by the server.

Keep the current SSH session open, then reload the service. On Ubuntu and Debian, run:

Terminal
sudo systemctl reload ssh

On Fedora, RHEL, and derivatives, run:

Terminal
sudo systemctl reload sshd

The new settings apply to new connections. Open a second terminal, connect again, and test the session before closing the original one. Client-side keepalives are usually enough, so you do not need to configure both ends for every connection.

ServerAliveInterval vs TCPKeepAlive

OpenSSH enables TCPKeepAlive by default, but operating-system TCP probes are not a replacement for ServerAliveInterval. TCP keepalives commonly wait much longer before sending anything, and their timing is controlled by kernel settings. SSH server-alive messages travel inside the encrypted connection and use the interval you specify.

Do not disable TCPKeepAlive as a first fix. Add ServerAliveInterval for predictable application-level checks, then leave the TCP behavior at its default unless you have a measured reason to change it.

Protect Long-Running Commands with tmux

A keepalive can reduce idle disconnects, but it cannot preserve a connection through every network change or a laptop losing power. To protect a long-running command, start it inside a tmux session on the server after logging in:

Terminal
tmux new -s maintenance

Start the command inside that session. To detach, press Ctrl+B, release both keys, then press d. If SSH drops, reconnect and attach to the existing session:

Terminal
tmux attach -t maintenance

The program keeps running in the server’s tmux session when the SSH connection closes. This does not protect it from a server reboot or the tmux session being terminated. See the tmux getting-started guide for installation, window, pane, and session commands.

Troubleshooting

The connection still drops with ServerAliveInterval set
Run ssh -G production | grep -i serveralive to confirm the effective settings. If you use SSH connection sharing , test with ssh -S none production to open a fresh connection instead of reusing a master connection with older settings. If the values are correct, compare the disconnect time with the client and server logs. Keepalives cannot prevent a full network outage or a server reboot.

SSH disconnects while output is actively printing
An idle timeout is unlikely because the connection already carries traffic. Check Wi-Fi, VPN, and packet loss on the client, then check the server logs for resource exhaustion or terminated SSH processes.

The server closes sessions after an exact fixed period
Check for ChannelTimeout in sudo sshd -T output on OpenSSH versions that support it, adding the -C options described above when the server uses Match rules. Unlike client-alive probes, a setting such as ChannelTimeout session=5m can close an inactive session even when the client is responding. Bash can also log out an idle shell through its TMOUT variable. Run printf '%s\n' "${TMOUT-unset}" in the remote Bash shell to inspect it, and check with the administrator before changing an intentional timeout policy.

The error appears immediately during login
Keepalive settings will not help an authentication or listening-port failure. Use the SSH connection refused guide for network and service errors, or the SSH permission denied guide for key authentication failures.

Conclusion

Start with client keepalives and check the logs if the connection still drops. Before starting a long-running job, open a tmux session on the server so you can reconnect to it after a network interruption.

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 1000+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page