核心是mysql端wait_timeout与interactive_timeout必须同步设置为相同值(如3600),并重启生效;同时连接池maxlifetime需设为略短(如3000000毫秒),且开启select 1有效性验证,云数据库则须通过客户端保活规避限制。

核心是让 MySQL 主动回收空闲连接的时间,和应用连接池的生命周期对齐——不是越长越好,也不是越短越安全,关键是“两端匹配”。
为什么必须同时改两个参数
绝大多数应用(JDBC、PHP PDO、Python SQLAlchemy)建立的是非交互式连接,它们在初始化时会把 interactive_timeout 的值复制给自己的 session.wait_timeout,而不是读取全局 wait_timeout。也就是说,只改 wait_timeout 是无效的。
所以必须同步设置:
- SET GLOBAL interactive_timeout = 3600;
- SET GLOBAL wait_timeout = 3600;
否则新连接仍可能沿用旧的 interactive_timeout(比如云数据库默认的 300 秒),导致空闲 5 分钟就被断开。
配置文件里怎么写才真正生效
临时 SET GLOBAL 命令在 MySQL 重启后丢失,生产环境必须写入配置文件。
编辑 /etc/my.cnf 或 /etc/mysql/my.cnf,在 [mysqld] 段下添加:
- wait_timeout = 3600
- interactive_timeout = 3600
注意:[client] 或 [mysql] 段下的设置对服务端无效;改完必须重启 MySQL:sudo systemctl restart mysql。
验证是否生效:登录后执行 SELECT @@wait_timeout, @@interactive_timeout;,看返回值是否为你设的数字。
光调 MySQL 还不够:连接池必须同步校准
如果连接池的空闲连接存活时间(如 HikariCP 的 maxLifetime 或 Druid 的 maxEvictableIdleTimeMillis)比 MySQL 的 wait_timeout 还长,连接就会在 MySQL 端被杀掉后,仍被池子当作“可用”返回给应用,引发 “MySQL server has gone away”。
建议策略:
- MySQL 端设为 3600(1 小时)
- 连接池端设 maxLifetime = 3000000(约 50 分钟),留出缓冲余量
- 开启连接有效性检测:如 connection-test-query=SELECT 1 或 validation-timeout=3000
这样连接在被 MySQL 断开前,就已被池子主动清理或验证失败淘汰。
云数据库用户特别注意
阿里云 RDS、腾讯云 CDB 等通常禁止修改 wait_timeout / interactive_timeout 的全局值。此时只能靠应用侧控制:
- 连接池配置中启用 keepalive 或定期执行 SELECT 1
- 将连接池的 idleTimeout 设为明显小于云厂商默认值(如设为 240 秒,避开默认 300 秒)
- 避免使用长事务或在事务中混入耗时非 DB 操作
本质是用更积极的客户端保活逻辑,弥补服务端不可调的限制。











