SFTP连接卡住的根本原因是中间网络设备静默丢弃空闲连接,而OpenSSH默认未启用有效保活机制;必须配置ServerAliveInterval(如45秒)和ServerAliveCountMax(如2)组合实现SSH层主动探测,TCPKeepAlive基本无效且不应禁用。

为什么 SFTP 连接卡在 “Connecting…” 或传输中途挂死
根本原因常是中间网络设备(如 NAT 网关、防火墙)静默丢弃了空闲连接,而 OpenSSH 默认不主动探测连接是否存活。客户端以为连着,服务端早已关闭,结果 ssh 或 sftp 命令卡住几秒到几十秒才超时——这不是 DNS、密钥认证或带宽问题,是 TCP 层保活没配对。
必须设的两个客户端参数:TCPKeepAlive、ServerAliveInterval 和 ServerAliveCountMax
TCPKeepAlive 是底层 TCP 保活开关(默认 yes),但它由内核控制,间隔长(通常 2 小时)、不可控,对 SSH 场景基本无效。真正起作用的是 SSH 层的主动探测机制:
-
ServerAliveInterval:客户端每隔多少秒发一个空包探测服务端是否在线(推荐设为30或60) -
ServerAliveCountMax:连续几次探测失败后断开连接(默认3,建议保持) - 二者必须一起用,单独设
ServerAliveInterval不生效 - 别碰
TCPKeepAlive no——关掉它不会加速,反而让连接更难被及时发现失效
怎么配:全局配置 vs 单次命令 vs sftp 子命令
配置位置优先级:命令行 > ~/.ssh/config > 系统 /etc/ssh/ssh_config。实操中推荐写进用户配置,一劳永逸:
Host myserver
HostName 192.168.1.100
User deploy
ServerAliveInterval 45
ServerAliveCountMax 2
如果只临时调试,直接加参数跑:
sftp -o ServerAliveInterval=30 -o ServerAliveCountMax=3 user@host
注意:sftp 命令本身不读取 ~/.ssh/config 的所有选项(老版本有坑),但现代 OpenSSH(≥7.0)已支持。若仍无效,换 ssh 测试确认配置是否加载成功:
ssh -o "ServerAliveInterval 30" -o "ServerAliveCountMax 2" user@host echo ok
容易被忽略的兼容性细节和副作用
某些老旧 SSH 服务端(如 OpenSSH ServerAlive 探测包,导致客户端提前断连;此时需降级为 TCPKeepAlive yes + 调大内核 net.ipv4.tcp_keepalive_time(不推荐,粒度太粗)。
-
ServerAliveInterval太小(如5)会增加无谓流量,对高延迟链路(如跨国)可能引发误判 -
ServerAliveCountMax设为1会让一次丢包就断连,实际网络抖动常见,2或3更稳妥 - 使用
sftp时若启用了ProxyCommand,保活包走的是代理链路,得确保代理本身也稳定——这点常被当成 SFTP 问题排查半天
真正卡顿的根因往往藏在第三层:不是参数没设,而是设了但没生效(比如配错 Host 别名、路径拼错、权限不对导致 config 被跳过)。先用 ssh -F /dev/null -o "ServerAliveInterval=15" -v user@host 看 debug 日志里有没有 Send SSH2_MSG_GLOBAL_REQUEST keepalive@openssh.com 出现。











