必须同时设置wait_timeout和interactive_timeout为相同值(如300~600),否则交互式连接仍按默认28800秒超时,导致sleep连接堆积;二者需写入my.cnf并重启mysql,且连接池maxlifetime须比wait_timeout少至少60秒以避免“mysql server has gone away”错误。

必须同时改 wait_timeout 和 interactive_timeout,否则 Sleep 连接照样堆积——只调一个等于白调。
为什么只改 wait_timeout 不起作用
MySQL 区分“非交互式连接”(比如 Java 应用、PHP 脚本)和“交互式连接”(比如命令行 mysql、Navicat、DBeaver)。wait_timeout 只管前者,interactive_timeout 才管后者。如果只设了 wait_timeout = 600,但 interactive_timeout 还是默认的 28800 秒,运维人员连上去查个表就留着窗口不关,几小时后就是一堆卡死的 Sleep 连接。
- 两者值必须一致,生产环境建议统一设为
300~600(5~10 分钟) - 不能只靠
SET GLOBAL临时改:权限不足、未持久化、重启即失效 - 必须写进配置文件(如
/etc/my.cnf的[mysqld]段),然后重启 MySQL 或发SIGHUP重载(取决于版本和启动方式)
connect_timeout 是防攻击的第一道门,别设成 60
connect_timeout 控制的是 TCP 握手 + 用户认证阶段的最大等待时间,不是空闲断连时间。它防的是 SYN Flood、弱口令暴力试探、DNS 解析卡住这类“半开连接”攻击。设太高(比如 30 秒以上),一个恶意 IP 就能长期占住一个连接槽位。
- 默认值
10秒已够用;网络差或用了 LDAP/PAM 认证时,可提到15,但绝不建议超过30 - 这个参数无法动态修改(
SET GLOBAL connect_timeout = ...会报错),必须写配置并重启 - 配合
max_connect_errors = 3使用,连续失败三次就封 IP(需开启skip-name-resolve避免 DNS 拖慢判断)
连接池的 maxLifetime 必须比 wait_timeout 少至少 60 秒
MySQL 主动断掉 Sleep 连接后,应用连接池若不知道,下次从池里取出这个“假活”连接,直接抛 MySQL server has gone away。这不是 MySQL 的错,是池子没对齐超时策略。
- HikariCP:设
maxLifetime = 540000(9 分钟),对应 MySQL 的wait_timeout = 600(10 分钟) - Druid:设
maxEvictableIdleTimeMillis = 540000,同理 - 禁用
testOnBorrow和validationQuery:每次取连接都查一次库,QPS 上千时 CPU 直接拉满 - 优先用
connectionInitSql = SELECT 1或 HikariCP 的keepaliveTime做轻量心跳
验证是否真生效,别信 SHOW VARIABLES
配置写了、命令执行了、服务也重启了,不代表就起效了。得看运行时行为:
- 跑
SHOW PROCESSLIST,找State = 'Sleep'且Time > 600的行——还有?说明要么参数没加载,要么连接正卡在事务里(SHOW ENGINE INNODB STATUS查事务) - 查
SHOW VARIABLES LIKE '%timeout%',确认wait_timeout和interactive_timeout真是你要的值,不是还挂着 28800 - 注意:旧连接不会立刻断,要等它们自然空闲超时;新连接才会按新参数走
最容易被忽略的点:interactive_timeout 被当成“开发用的,无所谓”,结果运维脚本、监控探针、定时备份工具全用交互式连接连上来,一跑完不退出,就堆成山。它和 wait_timeout 是同一枚硬币的两面,少一面,超时机制就塌一半。











