核心是同步调整wait_timeout与interactive_timeout并匹配连接池参数;需先查实际值(SELECT @@wait_timeout, @@interactive_timeout),再永久修改my.cnf中[mysqld]段并重启,同时配置HikariCP/Druid的maxLifetime、validationQuery及PDO/MySQLi客户端超时。

MySQL连接空闲超时自动断开,核心就是调 wait_timeout 和 interactive_timeout,但光改这两个参数不配套客户端行为,反而容易出“MySQL server has gone away”错误。
查清楚当前生效的 wait_timeout 值是多少
不同环境实际值可能和文档默认值(28800秒)差很远:云数据库可能设成300秒,phpEnv内置MySQL可能继承了发行版模板,JDBC驱动还可能带 CLIENT_INTERACTIVE 标志导致走 interactive_timeout 路径。别猜,直接连上去查:
SELECT @@wait_timeout, @@interactive_timeout;
注意返回单位是秒;如果两个值不一致,说明服务端行为已分裂,后续排查会绕弯子。
永久修改必须改 my.cnf 并重启 mysqld
临时执行 SET GLOBAL wait_timeout = 600 看似快,但 MySQL 一重启就回滚,而且新连接是否继承还取决于配置文件读取顺序。生产或稳定开发环境务必编辑配置文件:
- Linux/macOS 下找
/etc/my.cnf或/etc/mysql/my.cnf;phpEnv 用户看/usr/local/phpenv/config/mysql/my.cnf或C:\phpEnv\config\mysql\my.ini - 只在
[mysqld]段落下加两行:wait_timeout = 600和interactive_timeout = 600 - 删掉
[client]段落里同名配置——那只是给mysql命令行用的,不影响服务端判定 - 改完必须执行
sudo systemctl restart mysql(不是reload),否则零生效
HikariCP/Druid 连接池比数据库参数更关键
把 wait_timeout 设成 600 秒(10 分钟),但 HikariCP 的 maxLifetime 默认是 1800000 毫秒(30 分钟),连接池根本等不到 MySQL 断它,自己先销毁了;反过来,如果设成 3600 秒(1 小时),而连接池 idleTimeout 是 600000 毫秒(10 分钟),那连接大概率在被 MySQL 杀之前就被池子回收了——所以真正要稳,得让 MySQL 的断开时间略大于连接池的 maxLifetime,且必须开启验证机制:
- HikariCP 推荐配:
connection-test-query=SELECT 1(MySQL 8.0+ 可用isValid()代替) - Druid 配:
testOnBorrow=true+validationQuery=SELECT 1 - 别信
autoReconnect=true—— MySQL 5.5+ 已废弃,它不重连,只抛CommunicationsException,还可能破坏事务一致性
PDO/MySQLi 客户端连接阶段超时不能漏
服务端 wait_timeout 解决的是“连上了但不动”,但建连卡在 TCP 握手、DNS 解析慢、防火墙拦截时,PHP 进程会一直 hang 住。这时得靠客户端显式设连接超时:
PDO 推荐用选项数组(兼容性更好):
$options = [
PDO::MYSQL_ATTR_CONNECT_TIMEOUT => 5,
PDO::MYSQL_ATTR_READ_TIMEOUT => 10,
PDO::MYSQL_ATTR_WRITE_TIMEOUT => 10,
];
MySQLi 必须三步走:mysqli_init() → mysqli_options() → mysqli_real_connect();直接 mysqli_connect() 传参无效。CLI 脚本或队列任务尤其要注意这点——长驻进程一旦卡住,整个 worker 就废了。
最常被忽略的是:改完 wait_timeout 后没同步调连接池参数,或者忘了在 PHP 代码里加客户端 connect timeout,结果问题照旧。空闲断连从来不是单点问题,而是服务端、连接池、客户端三层对齐的结果。


















