
SSH 连接被服务端主动断开的典型表现
你执行命令到一半,终端突然卡住几秒后显示 Connection closed by remote host 或直接断连,且本地 ssh 进程退出。这不是网络抖动导致的临时丢包,而是服务端(sshd)主动终止了连接。
根本原因通常是服务端设置了空闲超时策略。OpenSSH 默认启用 ClientAliveInterval 和 ClientAliveCountMax 机制:若客户端在指定时间内未发任何数据包,sshd 会发送探测包;连续几次无响应就 kill 掉该连接。
常见错误配置包括:
-
ClientAliveInterval 0(禁用探测)但搭配了TCPKeepAlive no,导致内核无法感知链路异常 -
ClientAliveInterval 60且ClientAliveCountMax 3,意味着最多 3 分钟无交互就会断连 -
MaxStartups或MaxSessions被设得过低,高并发时新连接被拒绝或旧连接被踢出
如何确认是服务端配置导致的断连
登录服务器后检查 /etc/ssh/sshd_config 中的关键项,并比对当前生效值:
运行 sudo sshd -T | grep -E "(clientalive|tcpkeepalive|maxstart|maxsess)" 获取实际加载的配置(注意:此命令需 root 权限,且不校验语法,仅输出合并后的结果)。
重点关注以下字段是否被显式修改过:
-
ClientAliveInterval:非零值即启用保活探测,单位秒 -
ClientAliveCountMax:默认 3,表示允许连续丢失多少次探测响应 -
TCPKeepAlive:设为yes可让内核在传输层维持连接,但对 NAT 网关不友好 -
MaxStartups:如设为10:30:60表示最多 10 个未认证连接,超过后按概率丢弃
如果发现 ClientAliveInterval 是 60、120 或其他较小值,基本可锁定问题来源。
客户端侧快速绕过断连的实操方式
无需改服务器配置,也能稳定长连接。在本地 SSH 客户端加保活参数即可:
- 临时使用:
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 user@host - 永久生效:编辑
~/.ssh/config,加入对应 Host 块:Host myserver
HostName 192.168.1.100
User admin
ServerAliveInterval 30
ServerAliveCountMax 3 -
ServerAliveInterval必须小于服务端的ClientAliveInterval,否则探测包赶不上服务端判定节奏 - 避免设
ServerAliveInterval 0—— 这会禁用客户端保活,完全依赖服务端策略
注意:ServerAlive* 是客户端行为,只影响本机发起的连接;而 ClientAlive* 是服务端行为,影响所有接入的客户端。
排查 NAT 或中间设备干扰的必要步骤
即使服务端和客户端都配了保活,仍可能因路由器、防火墙、云平台 SLB 清理空闲连接而断连。这类断连通常没有日志痕迹,且复现不稳定。
验证方法:
- 在客户端执行
ping -i 30 target_ip同时保持 SSH 连接,观察是否还断——若不断,说明是纯空闲导致;若仍断,大概率是中间设备干的 - 用
tcpdump -i any port 22抓包,看最后收到的是否为 RST 或 FIN 包,以及源 IP 是否来自网关而非目标服务器 - 云服务器(如阿里云、AWS)需检查安全组/网络 ACL 是否启用了“连接空闲超时”,该值常为 900 秒(15 分钟),且不可调
这种场景下,唯一可靠解法是客户端持续发送保活帧,ServerAliveInterval 建议设为 300(5 分钟)以内,避开中间设备阈值。
真正麻烦的是那些既没日志、又不回 RST 的“静默丢包”设备——它们会让 SSH 卡住几十秒才报错,此时必须结合 ConnectTimeout 和重试逻辑做容错,而不是指望一次配置解决所有问题。










