The "client_loop: send disconnect: Broken pipe" error occurs when an idle SSH connection is terminated by the server, firewall, or NAT device due to inactivity timeout. It's common in remote work and cloud environments where keepalive settings aren't configured.
This error appears when your SSH session becomes inactive for too long and the server (or an intermediate firewall/NAT/router) closes the connection. SSH is a stateful protocol—if no data flows for several minutes, network infrastructure assumes the connection is dead and terminates it. When your client tries to send the next command, it discovers the broken pipe and displays this error. This is purely a connectivity issue—your credentials and permissions are fine; the connection itself was dropped.
Configure your SSH client to send keepalive packets every 60 seconds. Add to ~/.ssh/config:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3This tells your SSH client to send a null packet every 60 seconds to keep the connection alive. ServerAliveCountMax 3 means it will retry 3 times before giving up (total: 180 seconds of no response).
Alternatively, use on command-line for one-off connections:
ssh -o ServerAliveInterval=60 user@hostnameThis is the most reliable client-side fix and works immediately without server changes.
Add TCPKeepAlive to your SSH config to send TCP-level keepalives:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yesTCPKeepAlive uses lower-level TCP keepalive probes. Combined with ServerAliveInterval, this provides redundant keepalive mechanisms and is especially useful if SSH-level keepalives alone aren't working.
If you have access to the SSH server, configure server-side keepalive settings. Edit /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_configAdd or update:
ClientAliveInterval 300
ClientAliveCountMax 3This tells the server to send a keepalive packet every 300 seconds (5 minutes) if no activity from client, retrying 3 times.
After editing, restart SSH service:
sudo systemctl restart sshdServerAliveInterval on the client is usually enough, but server-side config helps when many clients connect with stale settings.
If you experience disconnects on a specific network (VPN, corporate firewall), reduce the ServerAliveInterval to send packets more frequently:
Host restrictive-network
ServerAliveInterval 30
ServerAliveCountMax 5
TCPKeepAlive yesThis sends keepalive packets every 30 seconds (instead of 60), which stays ahead of aggressive firewall timeouts (typically 5-15 minutes).
For particularly troublesome networks:
Host very-restrictive
ServerAliveInterval 20
ServerAliveCountMax 3
TCPKeepAlive yes
ExitOnForwardFailure yesLower intervals use slightly more bandwidth but guarantee the connection never sits idle.
If SSH keepalive settings don't solve the problem (especially for mobile/WiFi), consider using mosh (mobile shell):
sudo apt-get install mosh # Debian/Ubuntu
sudo yum install mosh # RHEL/CentOS
brew install mosh # macOSThen connect:
mosh user@hostnameMosh is designed for mobile/unreliable connections:
- Tolerates network changes (WiFi to cellular)
- Automatically reconnects on temporary network loss
- Lower bandwidth usage
- Supports disconnecting/reconnecting without losing session
Mosh runs on top of SSH, so your server still needs SSH; it's a better shell for roaming connections.
If keepalive settings don't resolve the issue, your network may have aggressive filtering:
# Test if packets are actually being sent
ssh -vv user@hostnameLook for lines like "Sending SSH2_MSG_IGNORE" or "Packet type..." which confirm keepalive is active.
If still disconnecting:
- Check if you're behind a corporate proxy (ask your network admin)
- Test on a different network (home WiFi, cellular hotspot, VPN)
- Contact your ISP if it's a home internet issue
- For cloud VMs, check the security group/firewall rules allow outbound SSH
If behind a proxy:
Host proxy-host
ProxyCommand ssh bastion-host 'nc %h %p'
ServerAliveInterval 60Ensure keepalive settings are on both the client and bastion connections.
Advanced Troubleshooting:
Ubuntu 24.04+ Behavior Change: Ubuntu 24.04 and later changed SSH default keepalive behavior. If you recently upgraded and now see broken pipe errors, add explicit TCPKeepAlive settings to restore previous behavior.
EC2 and Cloud VMs: Amazon AWS and other cloud providers often use aggressive NAT timeouts (5-15 minutes). Always set ServerAliveInterval to 60 or lower on connections to cloud instances.
SSH Tunnels and Port Forwarding: Tunnels with -L or -R flags are especially susceptible to idle timeouts. Apply keepalive settings twice: once for the tunnel itself, once in ~/.ssh/config for the host.
Bastion/Jump Host Connections: When using ssh -J bastion-host target-host, timeouts can occur on either leg. Enable keepalive on both:
Host target-host
ProxyJump bastion-host
ServerAliveInterval 60
ServerAliveCountMax 3
Host bastion-host
ServerAliveInterval 60
ServerAliveCountMax 3VPN and Proxy Environments: Corporate VPNs and proxies have their own timeout settings (often very aggressive). If ServerAliveInterval 60 fails, reduce to ServerAliveInterval 30. Contact your network team for the VPN's idle timeout value.
Debugging: Run ssh with verbose flags to confirm keepalives are active:
ssh -vv user@host # Shows "Sending SSH2_MSG_IGNORE" packetsMosh Alternative: For truly unreliable networks (mobile, WiFi roaming), mosh is superior. It tolerates network changes SSH cannot handle. However, it requires mosh to be installed on both client and server.
Load key "/home/user/.ssh/id_rsa": invalid format
How to fix 'Load key invalid format' in SSH
Bad owner or permissions on /home/user/.ssh/config
How to fix "Bad owner or permissions on .ssh/config" in SSH
Error connecting to agent: Connection refused
How to fix "Error connecting to agent: Connection refused" in SSH
Connection closed by UNKNOWN port 65535
How to fix 'Connection closed by UNKNOWN port 65535' in SSH
Offending ECDSA key in /home/user/.ssh/known_hosts:line
How to fix "Offending ECDSA key in known_hosts" in SSH