"ssh 卡住不动,半天之后弹出一句 Connection timed out"——同样是超时,原因可能天差地别:可能是安全组没放行 22 端口,可能是 sshd 挂了,可能是 DNS 反查拖慢了握手,也可能是密钥文件权限不对导致认证反复失败。盲目重启服务往往白费功夫。本文把 SSH 超时拆成连接阶段超时、认证阶段超时、空闲断连三类,分别给出定位方法和对应的命令,让你能在几分钟内分清是哪一层出了问题。
一、先分类:三种"超时"现象与对应方向
| 现象 | 典型报错 | 问题所在层 | 首要排查命令 |
|---|---|---|---|
| 敲完命令后长时间无响应,最终报错 | Connection timed out(约 60-130 秒后) | 网络层:路由不通、防火墙 DROP | ping、mtr、nc -zv IP 22 |
| 立刻被拒绝 | Connection refused | 端口无监听:sshd 未运行或改了端口 | ss -lntp、systemctl status sshd |
| 连上了但一直卡在认证 | 卡在 "Authenticating with..." 或反复要求密码 | 认证层:DNS 反查、密钥权限、PAM | ssh -vvv、journalctl -u sshd |
| 连上后一段时间不动就断开 | Connection reset by peer / 卡死 | 保活层:NAT 会话超时、防火墙空闲切断 | ClientAliveInterval、ServerAliveInterval |
| 提示主机密钥变更 | REMOTE HOST IDENTIFICATION HAS CHANGED | known_hosts 记录冲突 | ssh-keygen -R IP |
第一步一定要先做这个区分,它决定了后面 80% 的排查方向。Connection timed out 与 Connection refused 是完全不同的两件事:前者是数据包发出去没人回应(被防火墙静默丢弃或路由不可达),后者是对方明确回复了 RST(端口上没有进程监听)。
二、网络层排查:从本机到目标逐段确认
# 1. 基本连通性(注意:禁 ICMP 的机器 ping 不通不代表 SSH 不通) ping -c 4 10.0.0.10 # 2. 端口连通性测试(最关键的一步) nc -zv -w 5 10.0.0.10 22 # 或没有 nc 时用 bash 内置 timeout 5 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.10/22' && echo "端口通" || echo "端口不通" # 或用 ssh 自带参数 ssh -o ConnectTimeout=5 -o BatchMode=yes root@10.0.0.10 true # 3. 路径追踪,看卡在第几跳 traceroute -n -T -p 22 10.0.0.10 mtr -n -T -P 22 --report 10.0.0.10 # 4. 确认 DNS 解析是否正确(域名登录时) dig +short example.com nslookup example.com
怎么读结果:nc -zv 返回 succeeded 说明 TCP 三次握手成功,问题在 SSH 协议层(认证/版本/算法);返回 timed out 说明包被丢,去查防火墙与安全组;返回 Connection refused 说明主机活着但 22 端口无监听。
2.1 防火墙与安全组
# firewalld firewall-cmd --state firewall-cmd --list-all firewall-cmd --list-ports firewall-cmd --permanent --add-service=ssh firewall-cmd --permanent --add-port=2222/tcp firewall-cmd --reload # iptables iptables -L -n -v | grep -E '22|ssh' iptables -L INPUT -n --line-numbers # 查看是否被 fail2ban 封禁 fail2ban-client status sshd iptables -L f2b-sshd -n -v
云服务器还有一个高频原因:厂商安全组没放行。这一点在操作系统层面完全查不出来,必须登录云控制台确认入站规则。判断标准:如果同 VPC 内其他机器能连、外网连不上,且本机防火墙已放行,八成是安全组或网络 ACL 的问题。
2.2 源 IP 变化导致的超时
家里宽带重拨后 IP 变了,而安全组或 iptables 写死了旧 IP,就会出现"昨天还能连今天不行"。排查时用 curl ifconfig.me 看自己当前的公网出口 IP,与白名单比对即可。
三、服务层排查:sshd 是否活着、监听是否正确
# 服务状态 systemctl status sshd systemctl is-enabled sshd # 是否监听及监听地址 ss -lntp | grep -E ':22|:2222' ss -lntp sport = :22 # 服务日志(最有价值) journalctl -u sshd -n 100 --no-pager journalctl -u sshd -f # 实时跟随,配合客户端重连观察 # RHEL/CentOS 传统日志 tail -100 /var/log/secure # Ubuntu/Debian tail -100 /var/log/auth.log # 配置文件语法检查 sshd -t sshd -T | grep -E '^(port|listenaddress|permitrootlogin|passwordauthentication|maxauthtries|logingracetime|usedns|clientalive)'
sshd -T 会输出生效中的完整配置(含默认值与 include 进来的片段),比直接读配置文件可靠得多,排查配置类问题时应以它的输出为准。常见的监听问题:
- ListenAddress 配错:只监听了内网网卡 IP,从公网连自然超时。用
ss -lntp看到192.168.1.10:22而不是0.0.0.0:22就是这种情况。 - 改了端口但忘了放行:改成 2222 后 firewalld 没开、SELinux 也会拦截非标准端口(RHEL 上需要
semanage port -a -t ssh_port_t -p tcp 2222)。 - sshd 进程僵死:日志里有 "error: beginning MaxStartups throttling" 说明并发未认证连接过多被限流。
四、认证层排查:连上了却进不去
这一层最容易被误判成"网络问题"。用 -vvv 打开详细日志,能看到卡在哪一步:
ssh -vvv -o ConnectTimeout=10 user@10.0.0.10 # 只看关键阶段 ssh -vvv user@10.0.0.10 2>&1 | grep -E 'debug1: (Connecting|Connection established|Offering|Authentications|Next auth|Authenticated)'
输出的关键节点依次是:SSH2 版本协商 → 密钥交换(KEX)→ 服务端主机密钥校验 → 认证方式协商(publickey/gssapi-keyex/.../password)→ 认证结果。如果停在 "Authentications that can continue: publickey" 之后就没动静,说明公钥认证失败且没启用密码认证。
4.1 卡在 DNS 反查(经典慢问题)
sshd 默认会对客户端 IP 做反向 DNS 解析,DNS 服务器不可达时会卡十几秒甚至更久。表现是"能连上,但要等很久才出密码提示"。
# /etc/ssh/sshd_config UseDNS no GSSAPIAuthentication no
# 改完生效 sshd -t && systemctl reload sshd
排查依据:在服务器上抓 journalctl -u sshd -f,如果看到连接进来后长时间无日志,且 dig -x 客户端IP 很慢,基本可确认。同时检查 /etc/resolv.conf 里的 DNS 是否可达。
4.2 密钥认证失败
# 客户端:指定私钥并输出详细过程 ssh -i ~/.ssh/id_ed25519 -vvv user@10.0.0.10 # 服务端检查授权文件权限(权限不对会被直接忽略,这是头号原因) chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod 600 ~/.ssh/id_rsa chown -R user:user ~/.ssh restorecon -R ~/.ssh # RHEL 系 SELinux 环境需要 # 查看服务端拒绝原因 grep -iE 'authentication refused|bad ownership|Failed publickey|invalid user' /var/log/secure
日志里 Authentication refused: bad ownership or modes for directory /home/user 是标志性报错,意思是家目录或 .ssh 目录权限太宽松(比如家目录是 777),sshd 出于安全考虑拒绝使用其中的密钥。修正:chmod 755 /home/user、chmod 700 /home/user/.ssh、chmod 600 /home/user/.ssh/authorized_keys。
4.3 authorized_keys 内容与格式
# 追加公钥(推荐用 ssh-copy-id,避免格式错误)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@10.0.0.10
# 手动追加时确保是一行,且带有正确的算法前缀
cat ~/.ssh/id_ed25519.pub | ssh user@10.0.0.10 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
# 检查服务端文件每行格式
awk '{print NF, $1}' ~/.ssh/authorized_keys # 每行应以 ssh-ed25519/ssh-rsa 等开头
4.4 主机密钥变更告警
# 服务端重装后客户端报 REMOTE HOST IDENTIFICATION HAS CHANGED ssh-keygen -R 10.0.0.10 ssh-keygen -R '[10.0.0.10]:2222' # 非标准端口要带方括号 # 或直接编辑 vi ~/.ssh/known_hosts # 仅测试环境可临时跳过校验(生产不建议) ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@10.0.0.10
4.5 握手阶段"假超时":算法不匹配
OpenSSH 8.8 之后默认禁用了 ssh-rsa(SHA-1 签名)算法,老客户端、老交换机、堡垒机或嵌入式设备连接新服务端时,会报 "no matching host key type found" 或直接卡在密钥交换阶段,从使用感受上看非常像网络超时。判断依据:用 ssh -vvv 时如果看到 "no mutual signature algorithm" 或 "Unable to negotiate with x.x.x.x port 22",就是算法协商失败而不是网络问题。
# 列出本机支持的算法,与对端对比
ssh -Q key
ssh -Q kex
ssh -Q cipher
# 服务端针对特定主机临时放开老算法(/etc/ssh/sshd_config)
Host old-switch 10.0.0.253
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa
# 客户端临时放开(~/.ssh/config)
Host 10.0.0.253
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa
优先方案永远是升级客户端或服务端;必须兼容老设备时,务必写成 Host 段只匹配特定 IP,不要全局放开 ssh-rsa,否则等于降低了整机的安全基线。改完同样要 sshd -t 校验再 reload。
另一种"假超时"来自跳板机配置:客户端 ~/.ssh/config 或 /etc/ssh/ssh_config 里如果配了 ProxyCommand、ProxyJump,那么连不上的是跳板机,报错却指向目标机。排查时用 ssh -G 目标主机 | grep -i proxy 可以直接看到生效的代理配置,避免在网络层白费功夫。
五、空闲断连:连上不用就掉线
这类问题不是"连不上",而是"连上后放着几分钟就断"。原因是中间设备(NAT 网关、防火墙、负载均衡)会清理空闲会话表项。
# 服务端:/etc/ssh/sshd_config ClientAliveInterval 60 # 每 60 秒发一次保活探测 ClientAliveCountMax 3 # 连续 3 次无响应才断开(即约 180 秒) TCPKeepAlive yes
# 客户端:/etc/ssh/ssh_config 或 ~/.ssh/ssh_config
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
ConnectTimeout 10
ConnectionAttempts 2
# 临时命令行指定 ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@10.0.0.10 # 已有会话防中断(配合 tmux/screen 使用,断线后命令继续跑) tmux new -s ops
判断标准:如果断开总是发生在"闲置 5 分钟左右",而持续有输出时从不中断,几乎可以确定是空闲会话超时,配置保活即可解决。长期运维建议同时用 tmux/screen,把断线的影响降到最低。
六、标准排查步骤清单
- 明确报错原文:timed out / refused / reset / 主机密钥变更,先归到上表的某一类。
- 缩短等待时间:
ssh -o ConnectTimeout=5,别每次干等两分钟。 - 测端口:
nc -zv -w 5 IP 22。通 → 进第 6 步;超时 → 进第 4 步;refused → 进第 5 步。 - 网络不通:依次检查云安全组 → 本机 firewalld/iptables → 路由(mtr)→ 源 IP 白名单是否过期 → fail2ban 是否封了自己。
- 端口未监听:通过云控制台 VNC 或带外管理口登录,
systemctl status sshd、ss -lntp、journalctl -u sshd -n 100,确认服务是否启动、端口是否被改。 - 协议/认证层:
ssh -vvv定位卡点;服务端同步journalctl -u sshd -f观察。 - 针对性修复:DNS 反查 → UseDNS no;密钥权限 → chmod 700/600;主机密钥变更 → ssh-keygen -R;空闲断连 → 配 ClientAlive/ServerAlive。
- 验证:修复后先
sshd -t校验语法,用 reload 而非 restart,并保持一个已登录会话不断开。 - 留后路:确认云控制台 VNC/串行控制台可用,这是 SSH 彻底失联时的唯一救命通道,务必提前验证一次。
小结
SSH 连接超时的排查核心是分层与分类:先用 nc 把问题界定在"网络不通""端口没监听""认证失败""空闲被切"四类之一,再针对性深入。日常配置上,把 UseDNS no、GSSAPIAuthentication no、ClientAliveInterval 写进基线模板,能预防一大半的"慢"和"掉线";把密钥权限 700/600 当成铁律,能避免绝大多数免密失效。最后请务必提前验证带外控制台可用——那是所有 SSH 排障手段失效时的最后一道保险。
避坑清单
- 不要一上来就 restart sshd,配置错误会导致起不来;用
sshd -t+reload,并保持一个已登录会话。 - ping 不通 ≠ SSH 不通,很多机器禁 ICMP,判断端口通断要用 nc 或 /dev/tcp。
- 非 22 端口在 SELinux 环境需要单独放行,否则 sshd 会启动失败:
semanage port -a -t ssh_port_t -p tcp 2222。 - 家目录权限过松会让密钥认证静默失效,日志只说 bad ownership,不查日志很难想到。
- 改端口后务必同步更新防火墙、安全组、堡垒机与自动化脚本,漏一处就会出现部分人连不上。
- 不要长期用 StrictHostKeyChecking=no,会失去中间人攻击防护;正常做法是 ssh-keygen -R 清除旧记录。
- 批量运维前先单机验证,尤其是改 sshd_config,避免把全部机器锁死。
- MaxStartups 默认值(10:30:100)在批量并发连接时会限流导致超时,自动化场景可适当调大。
企业QQ咨询




