根本原因是wait_timeout和interactive_timeout设置过低,导致mysql主动断开空闲连接;需在my.cnf中全局配置并同步调整连接池空闲超时参数,否则仅加重连逻辑治标不治本。

MySQL连接断开后重连失败或反复中断,根本原因往往不是重连逻辑本身,而是wait_timeout和interactive_timeout设得太低,导致连接在应用层还没反应过来时就被MySQL单方面杀掉了。
为什么改这两个参数比写重连代码更关键
很多开发者一看到The last packet successfully received from the server就急着加autoReconnect=true或封装重试逻辑,但问题根源常在服务端:MySQL默认wait_timeout=28800(8小时),但某些云厂商或Docker镜像会悄悄改成300(5分钟);而应用连接池若没配置心跳或空闲检测,连接就会静默失效。
此时即使应用捕获异常并重连,也掩盖了资源浪费和事务不一致风险——比如一个长事务中途被MySQL断开,autoReconnect会强制回滚且无法恢复上下文。
-
wait_timeout控制非交互式连接(如JDBC、PHP mysqli)的空闲超时 -
interactive_timeout控制交互式连接(如mysql客户端)的空闲超时 - 两者默认值可能不同,但应用连接几乎全走
wait_timeout路径 - 修改需同时设
GLOBAL级,否则只影响当前会话
怎么安全地调高timeout值
直接执行SET GLOBAL wait_timeout=3600能临时生效,但MySQL重启就丢失。生产环境必须写进配置文件,并配合连接池行为校准。
- 在
/etc/my.cnf或/etc/mysql/my.cnf的[mysqld]段下添加:
wait_timeout = 3600 interactive_timeout = 3600
- 数值建议从
3600(1小时)起步,不要盲目设成28800;过高会积压大量空闲连接,触发Too many connections错误 - 改完必须执行
sudo systemctl restart mysql或sudo service mysqld restart,仅SET PERSIST在部分MySQL 8.0+版本可用,但不保证兼容所有部署形态 - 验证是否生效:
SHOW VARIABLES LIKE 'wait_timeout';,注意看Value列,不是Default
连接池配置必须同步调整
光调MySQL端没用。如果连接池的maxIdleTime或idleTimeout比wait_timeout还短,连接会在MySQL断开前就被池子主动回收,反而引发更多“连接已关闭”异常。
- HikariCP:确保
connection-timeoutidle-timeout wait_timeout,例如设idle-timeout=1800000(30分钟) - Druid:检查
min-idle和time-between-eviction-runs-millis,避免驱逐间隔过短 - 所有连接池都应开启
test-on-borrow或validation-query=SELECT 1,但别用test-while-idle高频心跳——它会放大QPS,尤其在读多写少场景
autoReconnect=true 是个危险开关
MySQL官方明确不推荐,因为它是“断开后新建连接”,而非“续接原连接”。启用后会出现:
- 正在执行的事务被无提示回滚,
COMMIT或ROLLBACK失效 - 表锁、行锁全部释放,可能引发数据竞争
- 会话变量(如
@user_id)、临时表、预编译语句全部丢失 - 连接ID变更,
SHOW PROCESSLIST里看不到连续操作痕迹
真要用,仅限调试阶段,且必须配合应用层幂等设计;生产环境宁可调timeout+配健康检测,也不要依赖它。
最易被忽略的一点:wait_timeout和interactive_timeout是**服务端参数**,而连接池的空闲策略是**客户端行为**,两者必须对齐,否则永远在打补丁。











