只改 mysql 的 wait_timeout 不够,必须同步调小连接池的 maxlifetime 和 idletimeout,否则照样报 “communications link failure”。因为 mysql 先断开空闲连接,而连接池未及时感知并清理,导致业务获取到已失效的“僵尸连接”而抛出异常。

直接结论:只改 MySQL 的 wait_timeout 不够,必须同步调小连接池的 maxLifetime 和 idleTimeout,否则照样报 “Communications link failure”。
为什么改了 wait_timeout 还是连不上
常见现象是应用偶尔报 MySQL server has gone away 或 Communications link failure,尤其在低峰后第一次请求时。这不是网络断了,而是 MySQL 已在后台把空闲连接关掉,但连接池还把它当“活连接”发给业务用。
-
wait_timeout默认 28800 秒(8 小时),太长,容易堆积僵死连接 - 连接池(如 HikariCP)默认
idleTimeout是 10 分钟,maxLifetime是 30 分钟,远大于 MySQL 的断连阈值 - 结果就是:MySQL 先动手杀连接 → 连接池没感知 → 下次取连接就炸
怎么安全设 wait_timeout 和 interactive_timeout
这两个参数必须一起设,且值一致——哪怕你不用交互式连接,也避免 ORM 或驱动行为不一致(比如某些 PyMySQL 版本会误设 CLIENT_INTERACTIVE 标志)。
- 查当前值:
SHOW GLOBAL VARIABLES LIKE '%timeout%'; - 临时生效(验证用):
SET GLOBAL wait_timeout = 300;+SET GLOBAL interactive_timeout = 300; - 永久生效:在
/etc/my.cnf的[mysqld]段加两行:wait_timeout = 300和interactive_timeout = 300 - 改完必须重启:
systemctl restart mysqld(Docker 环境用docker restart mysql) - 注意:Linux 下最小合法值是 1,设 0 无效;改太小(如 60)可能引发重连风暴,建议先从 300(5 分钟)起步
HikariCP / Druid 必须同步配哪几个参数
光调服务端等于白干。连接池得比 MySQL 更早“清理”连接,留出缓冲时间(建议小 10~20 秒)。
- HikariCP:
maxLifetime=290000(对应 MySQL 的 300 秒),idleTimeout=280000,再开connection-test-query=SELECT 1(MySQL 8.0.22+ 改用connection-init-sql=SELECT 1) - Druid:
testWhileIdle=true,timeBetweenEvictionRunsMillis=25000(25 秒检测一次),minEvictableIdleTimeMillis=280000 - JDBC URL 补充(可选):
?socketTimeout=30000&connectTimeout=5000,但这只管读写和建连超时,不解决空闲断连问题
容易被忽略的细节
真正卡住人的不是怎么设,而是谁在用哪个值、什么时候生效:
-
SET GLOBAL只影响新建立的连接,已存在的连接仍按旧值计时 - 云数据库(如阿里云 RDS)通常禁止改
wait_timeout,只能靠连接池侧兜底 - PHP 的
PDO::ATTR_TIMEOUT或 Python 的ping(True)是运行时检测,不能替代生命周期管理 - 如果用的是事务型长连接(比如 Django 的
CONN_MAX_AGE),更要确保它小于wait_timeout,否则事务中途连接被杀,回滚都来不及











