mysql远程连接超时需同步调整wait_timeout与interactive_timeout,并配合连接池maxlifetime、连接验证及jdbc超时参数,否则连接被服务端关闭后仍被复用,导致“mysql server has gone away”错误。

MySQL远程连接超时,不能只改wait_timeout,必须同步调整interactive_timeout,并配合应用层连接池配置,否则改了也白改。
为什么改了wait_timeout还是报“MySQL server has gone away”
这个错误不是连接建立失败,而是连接被服务端主动关闭后,应用还试图复用它。常见真实原因包括:
-
wait_timeout已生效,但连接池(如 HikariCP、Druid)没设maxLifetime,导致连接在 MySQL 端被杀后仍被取出使用 - 客户端发起大查询,超过
net_read_timeout,服务端中断读取,但 JDBC 没捕获异常或重试 - 中间件(如 ProxySQL、LVS、云厂商负载均衡)有自己的空闲超时,比 MySQL 更早断连,且不发 FIN 包,应用层无法感知
- 你只改了
wait_timeout,但某些驱动或 ORM(如旧版 Hibernate、PyMySQL 在特定 flag 下)会触发interactive_timeout路径,而该值仍是默认 28800(8 小时)
如何正确设置wait_timeout和interactive_timeout
这两个参数必须设为相同值,否则行为不可控——不是“可选”,是生产环境硬性建议。原因在于:
- 绝大多数 Java 应用(JDBC)、Python(PyMySQL/MySQLdb)、Node.js(mysql2)默认走非交互式连接,受
wait_timeout控制 - 但部分工具(如 Navicat、SQLyog、
mysql -u -p命令行)默认走交互式连接,受interactive_timeout控制 - 某些 ORM 或驱动在初始化时会误设
CLIENT_INTERACTIVE标志,导致同一应用里部分连接走interactive_timeout,部分走wait_timeout - 全局变量修改后,新连接才生效;已有连接仍沿用旧会话值,需重启连接池或等待其自然淘汰
推荐做法:在/etc/my.cnf的[mysqld]段下写死:
wait_timeout = 28800 interactive_timeout = 28800
然后重启 MySQL 服务。临时 SET GLOBAL 仅对后续新连接有效,且服务重启即丢失。
应用层必须做的三件事(否则数据库端调再久也没用)
数据库超时参数只管“空闲断连”,不管连接是否健康、能否执行 SQL。应用层必须补上这三层防护:
- 连接池设
maxLifetime略小于wait_timeout(例如设为 25200 秒 / 7 小时),强制连接在服务端关闭前退役 - 开启连接验证(如 HikariCP 的
connection-test-query=SELECT 1或validation-timeout),每次取连接前执行轻量检测 - 配置 JDBC URL 中的超时参数:
socketTimeout=30000(网络收发超时)、connectTimeout=5000(TCP 建连超时),避免卡死在底层 socket
别依赖autoReconnect=true——MySQL 5.5+ 已废弃该行为,且它只在连接异常中断后尝试重连,不解决连接复用失效问题。
怎么确认当前连接到底受哪个 timeout 控制
登录 MySQL 后执行:
SHOW PROCESSLIST;
观察你的连接状态是否为Sleep,再看Time列数值。如果接近你设的wait_timeout值(比如设了 3600,Time 显示 3598),说明是它在起作用。再查会话变量:
SHOW VARIABLES LIKE 'wait_timeout'; SHOW VARIABLES LIKE 'interactive_timeout';
注意:这里查的是**当前会话**的值,它由全局值 + 客户端类型共同决定。如果你用的是 JDBC,默认是非交互式,那会话wait_timeout就等于全局wait_timeout;但如果你用mysql --interactive连的,那会话wait_timeout就等于全局interactive_timeout。
最易被忽略的一点:很多团队只盯着数据库参数调优,却没检查中间件或云平台的连接空闲超时——它们往往默认 5~10 分钟,比 MySQL 还激进。这类断连不会触发 MySQL 的wait_timeout日志,但会导致一模一样的错误现象。











