TCP 已建立但在规定时间内未完成 TLS 握手,客户端报 TLS handshake timeout 的定位与修复
Go 客户端报 net/http: TLS handshake timeout,其他客户端可能显示 SSL_connect timeout、handshake timed out 或连接在 HTTPS 请求开始后长时间无响应。它发生在 TCP 连接已经建立之后、TLS 握手完成之前,通常由客户端的 TLS 握手超时触发,而不是 DNS 或 TCP 拨号超时。
要和 tls-handshake-failed 区分:握手失败往往很快返回 alert,例如证书、协议版本或加密套件不匹配;握手超时则是握手消息没有在截止时间内交换完,常见于丢包、延迟过大、MTU 黑洞、服务端过载或中间设备只转发了部分字节。TCP 能连上不代表 TLS 一定能完成,这正是排查的关键。
先确认卡在 TCP 还是 TLS 阶段:
curl -v --connect-timeout 3 --max-time 15 -o /dev/null \
-w 'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n' \
https://<host>/
openssl s_client -connect <host>:443 -servername <host> -state -brief </dev/null
openssl s_client -connect <host>:443 -servername <host> -tls1_2 -state </dev/null
ss -lnt '( sport = :443 )'
ss -tin '( dport = :443 or sport = :443 )'
mtr -n -T -P 443 -c 20 <host>
sudo ping -M do -s 1472 <host>
tcpdump -ni any -tttt 'host <host> and port 443'
journalctl -u <service> --since '30 min ago'
kubectl logs <ingress-pod> -n <ns> --tail=100
connect 有值但 tls 为 0,说明卡在握手;openssl s_client -state 会显示最后完成的握手步骤,能看出是等待 ServerHello、证书还是密钥交换。抓包重点看 ClientHello 是否发出、ServerHello 是否返回、证书包是否因过大而丢失,以及是否有大量重传。
服务端检查 TLS 终止进程的 CPU、连接数和证书加载方式:
top -H -p $(pgrep -f <tls-service> | head -1)
ss -s
openssl x509 -in /path/to/fullchain.pem -noout -subject -issuer -dates
Go 客户端应把拨号、TLS 握手和响应头超时分开配置,避免一个总超时掩盖具体阶段:
tr := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 3 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
}
client := &http.Client{Transport: tr, Timeout: 20 * time.Second}
HTTPS_PROXY 访问,代理的 CONNECT 建立后卡住或超时。curl 的分阶段耗时和 openssl s_client -state 定位最后完成的握手步骤,不要只调大超时。ping -M do 和 tracepath 验证路径 MTU,放行 ICMP 分片需求,必要时降低接口 MTU 或做 MSS clamping。NO_PROXY。合上页面,先回答,再展开对照。
TLS handshake timeout 和 tls: handshake failure 的含义有什么不同?curl 显示 connect 正常而 tls 为 0,下一步应查哪些点?ping -M do 逐级探测,配合抓包看大包是否丢失并检查 MSS clamping。openssl s_client -state 看最后完成的握手步骤,抓包确认 ClientHello 与 ServerHello 是否往返,并检查服务端 TLS 进程 CPU、握手队列、证书加载、代理 CONNECT 与防火墙转发。
小程序版
微信扫码,随时查命令