SSH 连不上服务器,是运维最"要命"的一类故障——因为它是你进去排查别的故障的入口。SSH 一旦不通,网站挂了你也进不去看,整个排障就卡在第一步。而且 SSH 的"连不上"有好几种完全不同的表现,很容易混:有的是敲了命令半天没反应最后超时(Connection timed out),有的是直接拒绝(Connection refused),有的是连上了但卡在输密码或登录后卡半天,还有的是登录能进但几分钟不动就被踢出来。这几种背后的原因天差地别。
这篇文章把 SSH 问题分成三个阶段来看:连不上(网络、安全组、防火墙、端口)、连得上但很慢(DNS 反解、GSSAPI 认证、PAM、motd)、连得上但会断(心跳保活、MTU)。每个阶段给出对应的排查工具和配置。读完你应该能明确判断"我这次卡在哪一阶段",并用最短的路径解决,而不是一上来就乱改 sshd 配置。
一、先明确"超时"长什么样
SSH 报错的措辞直接对应不同的问题,先学会读它:
| 报错 | 含义 | 方向 |
|---|---|---|
Connection timed out |
包发出去没有回应 | 网络不通、安全组丢弃、防火墙 DROP |
Connection refused |
主机可达但端口没开 | sshd 没启动、端口错、防火墙 REJECT |
No route to host |
路由不可达 | 路由/网关/网段问题 |
Permission denied |
认证失败 | 密钥/密码/用户问题(不是网络问题) |
Connection reset by peer |
连接被重置 | 中途被拦、sshd 异常、防护软件 |
| 连上后卡登录界面很久 | 认证阶段慢 | DNS 反解、GSSAPI、PAM |
| 登录后闲置一会儿断 | 会话保活失效 | 客户端/服务端心跳、NAT 超时 |
timed out 和 refused 的区别是关键:超时说明包被"静默丢弃"(防火墙 DROP 或网络不通),拒绝说明包到了、但没人监听。这两个的处理方向完全不同。
二、第一阶段:连不上
1. 分层确认连通性
# 先确认能不能到主机
ping -c 4
# 再确认 SSH 端口是否开放(默认 22)
nc -zv -w 3 22
telnet 22
# 如果改了端口,测对应端口
nc -zv -w 3 2222
# 看在哪一跳断的
traceroute
mtr -rw -c 20
判读:
ping不通、nc也超时:可能主机宕了、网络不通、或 ICMP+端口都被丢弃。继续用mtr看断点。ping通、nc 22超时:包到了主机但被丢弃,典型是防火墙 DROP 或云安全组没放行。nc 22返回Connection refused:主机在,但 22 端口没监听(sshd 没起或端口改了)。
2. 检查 SSH 服务端(需要能通过别的方式进机器)
如果还能用云控制台的 VNC/救援终端进去,检查 sshd:
# 服务状态
systemctl status sshd # RHEL/CentOS/Rocky
systemctl status ssh # Debian/Ubuntu
# 是否在监听、监听哪个地址和端口
ss -lntp | grep -E ':22|ssh'
# 注意监听地址:127.0.0.1:22 只接受本机;0.0.0.0:22 接受所有
# 看监听端口配置
grep -E '^Port|^ListenAddress' /etc/ssh/sshd_config
sshd -T | grep -E '^port|^listenaddress' # 打印最终生效配置
# 看日志
journalctl -u sshd -n 100 --no-pager
tail -n 100 /var/log/secure # RHEL 系
tail -n 100 /var/log/auth.log # Debian 系
3. 检查防火墙与安全组
这是"端口超时"第一大原因。注意要分两层查:云安全组和系统防火墙。
# 系统防火墙
# RHEL/CentOS/Rocky(firewalld)
sudo firewall-cmd --list-all
sudo firewall-cmd --list-ports
firewall-cmd --query-port=22/tcp
# 放行 SSH(若被误删)
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
# Debian/Ubuntu(ufw)
sudo ufw status verbose
sudo ufw allow 22/tcp
# 底层 iptables(有些环境直接用它)
sudo iptables -L -n -v | grep -E '22|ssh|DROP|REJECT'
# 云服务器还要去控制台确认安全组/网络 ACL 放行了 22 端口(或你改的端口)
# 入站规则要允许你的来源 IP 访问该端口
风险提示:远程改防火墙时,务必先留退路。用临时规则或 --timeout 先测试:
# firewalld 临时放行 60 秒,验证能连再永久保存
sudo firewall-cmd --add-port=22/tcp --timeout=60
# 确认新规则不会把自己挡在外面后,再 --permanent
如果把自己挡在外面了,只能通过云控制台的 VNC/串口进系统恢复。
4. 一个高频坑:改端口后忘了改防火墙
把 SSH 端口从 22 改成 2222 后,只改了 sshd_config 却没在防火墙/安全组放行 2222,是老手也会踩的坑。改端口务必同步处理防火墙,并保留一个已放行的旧端口会话不断开,确认新端口能连再关掉旧的。
三、第二阶段:连得上但很慢
现象是:nc 22 通,ssh 命令也能建立连接,但输密码前或登录后要等十几秒甚至更久。根源通常是服务端在连接建立时做了反向 DNS 查询或 GSSAPI 认证,而这些查询超时了。
1. 关闭 DNS 反解(UseDNS)
sshd 默认(或某些版本默认开启)会对客户端 IP 做反向解析,如果 DNS 不好使,就会卡到超时(常见几十秒)。
# 编辑 /etc/ssh/sshd_config
# UseDNS no
# 检查并修改
sudo sed -i 's/^#\?UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
sudo sshd -t # 校验语法
sudo systemctl reload sshd # RHEL 系;Debian 系是 ssh
2. 关闭 GSSAPI 认证
GSSAPI(Kerberos)认证在没配 Kerberos 的环境下会尝试并超时。
# /etc/ssh/sshd_config 中
# GSSAPIAuthentication no
# 客户端也在 /etc/ssh/ssh_config 里关
# GSSAPIAuthentication no
sudo sed -i 's/^#\?GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
sudo systemctl reload sshd
3. PAM 与 motd 拖慢登录
登录后卡顿,可能是 PAM 模块(如 pam_systemd、pam_unix 的 NSS 查询)或显示 motd 时执行了慢命令。
# 看 PAM 配置
cat /etc/pam.d/sshd
# 检查 NSS 是否配置了会超时的后端
grep -E '^passwd|^group|^hosts' /etc/nsswitch.conf
# 看登录脚本里有没有慢命令
cat /etc/profile /etc/bashrc
ls /etc/profile.d/
cat /etc/update-motd.d/* 2>/dev/null # Debian/Ubuntu 的 motd 脚本
# 用 strace 跟踪 sshd 登录过程,看卡在哪(在高负载或调试时慎用)
sudo strace -f -p $(pgrep -f 'sshd.*') 2>&1 | head -50
注意:strace 附加进程会有性能开销,生产环境尽量在测试环境做,或只在必要时短时间使用。
4. 客户端侧调优
# 客户端 ~/.ssh/config,避免每次卡顿
cat >> ~/.ssh/config <<'EOF'
Host myserver
HostName 203.0.113.10
User root
GSSAPIAuthentication no
# 跳过不必要的认证方式,加速连接
PreferredAuthentications publickey,password
EOF
chmod 600 ~/.ssh/config
四、第三阶段:连得上但会断
现象是能登录、能操作,但闲置一会儿(几分钟到十几分钟)后会话就"卡死"或断开,ssh 提示 Connection to ... closed 或 Write failed: Broken pipe。原因是空闲连接被中间的 NAT、防火墙、负载均衡回收了,或者双方心跳没开。
服务端保活
# /etc/ssh/sshd_config
# ClientAliveInterval 60 # 每 60 秒发一次心跳
# ClientAliveCountMax 3 # 连续 3 次无响应才断开(即最多约 180 秒)
sudo sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 60/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 3/' /etc/ssh/sshd_config
sudo systemctl reload sshd
客户端保活
# 客户端 ~/.ssh/config 或 /etc/ssh/ssh_config
# ServerAliveInterval 60 # 每 60 秒向服务器发心跳
# ServerAliveCountMax 3
cat >> ~/.ssh/config <<'EOF'
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
EOF
两端都配更保险。原则:客户端心跳间隔要小于中间设备(NAT/防火墙)的空闲超时时间(很多 NAT 默认 5–10 分钟)。
MTU 问题
如果断在传大文件、跑大命令时,或者某些操作后连接直接卡死,要怀疑 MTU。中间链路的 MTU 不匹配会导致大包被丢弃,TCP 又没正确分片,表现为"小操作正常、大传输卡死"。
# 探测路径 MTU(Don't Fragment)
ping -M do -s 1472 # 1472 + 28 = 1500,通了说明 MTU 1500
ping -M do -s 1400 # 逐步减小,找到能通的最大值
# 若 1472 不通、1400 通,说明路径 MTU 小于 1500,需要调低
# 临时降低本机 MTU
sudo ip link set dev eth0 mtu 1400
云环境(VXLAN、隧道)常见 MTU 是 1450 或更小。如果怀疑 MTU,可以在服务端/客户端把网卡 MTU 调低测试,确认后再固化。
五、用 ssh -vvv 定位卡点
ssh -vvv 会打印详细的连接和认证过程,是判断"卡在哪一步"的利器。
ssh -vvv user@203.0.113.10
输出很长,看关键节点:
- 卡在
Connecting to 203.0.113.10 port 22:TCP 连接阶段,网络/防火墙问题。 - 卡在
debug1: SSH2_MSG_KEXINIT sent之后无输出:密钥交换阶段,可能被拦或 MTU 问题。 - 卡在认证前(
Authentications that can continue之前很久):多半是 UseDNS/GSSAPI。 - 认证通过后卡住:PAM、motd、登录脚本。
配合工具一起用:
# 排查网络层
mtr -rw -c 20
traceroute
nc -zv -w 3 22
# 抓包(看 TCP 握手到了哪一步)
sudo tcpdump -i any -nn port 22 -c 50
# 看到 SYN 发出但没有 SYN-ACK,多半被墙(DROP)
# 看到 SYN-ACK 后又有 RST,可能被 REJECT 或 sshd 拒绝
抓包是终极手段:能明确区分"没收到回应(DROP/网络不通)"和"收到拒绝(REJECT/无监听)"。
六、配置调优清单
| 现象 | 调整项 | 位置 |
|---|---|---|
| 连接超时 | 安全组 + 防火墙放行端口 | 云控制台 / firewalld / ufw |
| 连接被拒 | 启动 sshd、确认端口 | systemctl、sshd_config |
| 登录慢(DNS) | UseDNS no |
/etc/ssh/sshd_config |
| 登录慢(GSSAPI) | GSSAPIAuthentication no |
服务端和客户端 |
| 会话超时断开 | ClientAliveInterval |
服务端 |
| 客户端侧保活 | ServerAliveInterval |
~/.ssh/config |
| 大传输卡死 | 调 MTU | ip link set mtu |
| 单 IP 频繁被扫 | MaxAuthTries、fail2ban |
sshd / fail2ban |
补充一个安全相关建议:SSH 是暴力破解重灾区,建议禁用密码登录、改用密钥,并配合 fail2ban 或云平台的高危端口防护。改 sshd_config 前务必先确认新配置能登录,改完先 sshd -t 校验,再 reopen 一个新会话验证,最后 reload,不要一下子 restart 把自己锁外面。
# 改配置的标准安全流程
sudo sshd -t # 1. 先校验语法
# 2. 保留当前会话不要断,另开一个新终端测试
ssh -p user@server
# 3. 新会话能进,再重载
sudo systemctl reload sshd
风险提示:sshd_config 改错是最经典的"把自己锁在服务器外面"。修改前备份 cp /etc/ssh/sshd_config{,.bak},全程保留一个已登录的会话不断开,用云控制台作为最后退路。
常见问题
Q:Connection timed out 和 Connection refused 有什么区别,怎么处理?
timed out 是包被静默丢弃,查网络和安全组/防火墙(DROP 规则);refused 是端口没监听,查 sshd 是否启动、端口是否改过。前者用 mtr/tcpdump,后者用 ss -lntp 和 sshd -T。
Q:能连上但每次登录要等十几秒,最可能是什么?
优先关 UseDNS no 和 GSSAPIAuthentication no,这两项是最常见的"登录慢"。其次是 PAM/NSS 查询和登录脚本里的慢命令。
Q:登录后不动几分钟就断,怎么解决?
配置保活。服务端 ClientAliveInterval 60 + ClientAliveCountMax 3,客户端 ServerAliveInterval 60。间隔要小于中间 NAT/防火墙的空闲超时。
Q:改了 SSH 端口就连不上了,怎么办?
先确认防火墙和安全组放行了新端口,ss -lntp 确认 sshd 监听在新端口,sshd -T | grep port 确认配置生效。若被锁在外面,用云控制台的 VNC/串口进去改回。
Q:大文件传输(scp/rsync)中途卡死,怎么排查?
多半是 MTU 问题。用 ping -M do -s 1472 探测路径 MTU,不通就逐步减小,找到合适的值后调低网卡 MTU(云环境常见 1450)。开启 tcp_mtu_probing 也可作为辅助。
总结
SSH 问题先分三阶段:连不上、连得上但慢、连得上但断。不同阶段原因和处理完全不同。
连不上:先 ping + nc -zv 分清是超时还是拒绝,超时查网络/安全组/防火墙(注意云安全组 + 系统防火墙两层),拒绝查 sshd 是否启动、端口是否改过。用 mtr、tcpdump 定位。
连得上但慢:罪魁通常是 UseDNS 反解和 GSSAPI 认证,在 sshd_config 里关掉(UseDNS no、GSSAPIAuthentication no),其次是 PAM/NSS 和登录脚本。
连得上但断:配置两端心跳保活(服务端 ClientAliveInterval,客户端 ServerAliveInterval),怀疑大包卡死就查 MTU。
排查工具首推 ssh -vvv,配合 nc、mtr、tcpdump。改任何 sshd_config 前,先备份、先校验(sshd -t)、保留活动会话、留好云控制台退路,避免把自己锁在服务器外面。
企业QQ咨询




