优先查tcp keepalive,因mysql连接中断多由中间设备(如云nat、防火墙)在空闲1–2小时后强制清理tcp连接所致;需调linux内核参数tcp_keepalive_time=600、intvl=60、probes=3,并确保客户端连接池idle-timeout小于wait_timeout,避免复用已断连。

MySQL连接中断集中在空闲1–2小时后,优先查TCP Keepalive
这不是MySQL自己关的,是中间设备(比如云厂商NAT、企业防火墙)先清掉了TCP连接。Linux内核默认tcp_keepalive_time=7200(2小时),而MySQL的wait_timeout通常是28800秒(8小时),探测还没开始,连接就被干掉了。
必须在MySQL服务器上改内核参数,不是改MySQL配置:
-
net.ipv4.tcp_keepalive_time = 600(空闲10分钟发第一个探测包) -
net.ipv4.tcp_keepalive_intvl = 60(每次探测间隔60秒) -
net.ipv4.tcp_keepalive_probes = 3(连续3次无响应才断连)
写进/etc/sysctl.conf后执行sysctl -p生效。改完用ss -i确认活跃连接是否真启用了keepalive。
Java应用用HikariCP时,idle-timeout设比wait_timeout还长?立刻踩坑
HikariCP的idle-timeout不是“等多久回收”,而是“空闲超过这个时间就主动关闭连接”。如果它大于MySQL的wait_timeout,连接池里那些没被回收的连接,会在服务端被KILL掉,下次复用直接报Communications link failure。
正确做法是让连接池比MySQL更早动手:
- 先查MySQL实际生效值:
SELECT @@wait_timeout(注意:SHOW VARIABLES返回的不一定是当前会话值) -
idle-timeout设为@@wait_timeout - 60,留出网络延迟和状态同步缓冲 - JDBC URL里必须显式加
&connectTimeout=3000&socketTimeout=30000,否则connection-timeout只控制池内等待,不控制建连失败
报错Lost connection during query,但SHOW PROCESSLIST里全是Sleep?那大概率是中间链路断的
如果错误总发生在长查询中途,且SHOW PROCESSLIST里对应线程状态是Sleep、Time值远小于wait_timeout,说明连接没被MySQL杀,是中间设备或网络层单方面RST了。
抓包验证最直接:
- 在应用服务器跑
tcpdump -i any port 3306 -w mysql.pcap - Wireshark里过滤
tcp.flags.reset == 1 - RST由MySQL IP发出 → 服务端主动终止(看
wait_timeout或OOM) - RST由客户端IP发出 或 RST前长时间静默(>30秒)→ 防火墙/NAT超时清理
别信autoReconnect=true,MySQL官方明确不推荐:事务回滚、锁释放、会话丢失,问题比症状更严重。
Too many connections但max_connections没满?盯紧TIME_WAIT和SYN_RECV
MySQL的max_connections只统计成功握手后的连接。大量新建连接失败,往往卡在TCP握手阶段。
用这条命令看真实瓶颈:netstat -an | grep :3306 | awk '{print $6}' | sort | uniq -c
- 输出里
TIME_WAIT多 → 客户端没调close(),短连接泄漏 -
SYN_RECV堆积 → TCP三次握手卡住,可能是SYN Flood、LB健康检查太密、或net.ipv4.tcp_max_syn_backlog太小 - 云环境还要查安全组/ACL连接速率限制(如阿里云SLB默认5000连接/秒)
连接数问题里,八成根子在应用代码——连接泄漏、长事务占着不放、或多个微服务共用一套连接池配置却没做总量约束。











