mysql连接自动断开是默认行为,由wait_timeout和interactive_timeout共同控制;jdbc等非交互式连接初始化时继承interactive_timeout值,故须同步修改二者才生效,且仅影响新建连接。

MySQL 连接“自动断开”不是 bug,而是默认行为 —— 由 wait_timeout 和 interactive_timeout 两个参数共同控制,且它们生效逻辑不同,不能只改一个。
为什么改了 wait_timeout 却没生效?
常见现象:执行 SET GLOBAL wait_timeout = 300 后,Java 应用还是在 8 小时后断连。原因在于:
– 非交互式连接(如 JDBC)的会话级 wait_timeout 值,在连接建立时就从 全局 interactive_timeout 继承,而非全局 wait_timeout;
– 换句话说,如果你只改了 wait_timeout 全局值,但没动 interactive_timeout,新建立的 JDBC 连接仍会拿到旧的 interactive_timeout 值(比如 28800),再把它当 wait_timeout 用。
验证方式:
– 连上 MySQL 后执行:SELECT @@session.wait_timeout, @@session.interactive_timeout;
– 若两者相等,说明当前会话是按 interactive_timeout 初始化的(典型非交互客户端行为)
真正要改,必须同步设置:
SET GLOBAL interactive_timeout = 300;SET GLOBAL wait_timeout = 300;
注意:这两个命令只对之后新建的连接生效,已有连接不受影响。
Java 应用连不上?先看你是哪种连接模式
JDBC 默认创建的是 非交互式连接,所以只受 wait_timeout 约束(但如上所述,其初始值来自 interactive_timeout)。而你用 mysql -u root -p 登录进来的终端是交互式连接,走的是 interactive_timeout。
关键区别:
- 交互式连接:MySQL 客户端、某些 CLI 工具、带
CLIENT_INTERACTIVE标志的 C API 调用 - 非交互式连接:JDBC、PDO、SQLAlchemy、大多数 ORM 和连接池创建的连接
因此,Java 项目出问题,99% 是 wait_timeout(实际继承自 interactive_timeout)太短,而不是配置漏了哪个参数。
连接池里怎么避免“拿了个已断的连接”?
即使你把服务端超时调到 24 小时,连接池(如 HikariCP、Druid)若不主动检测连接有效性,仍可能分配一个 MySQL 已关闭但本地未感知的连接。典型报错:CommunicationsException: The last packet successfully received from the server was ... ago。
实操建议(以 HikariCP 为例):
- 开启连接存活检测:
connection-test-query=SELECT 1(MySQL 8.0.19+ 推荐用connection-init-sql=SELECT 1) - 设置连接有效性超时:
validation-timeout=3000(单位毫秒) - 强制空闲连接回收:
idle-timeout=600000(比如 10 分钟,必须 wait_timeout) - 启用自动重连(不推荐长期依赖):
jdbcUrl中加&autoReconnect=true&failOverReadOnly=false,但注意它无法恢复事务上下文
重点:连接池的 idle-timeout 必须严格小于 MySQL 的 wait_timeout,否则池子里的空闲连接一定先被 MySQL 杀掉。
永久生效要改配置文件,别只靠 SET
SET GLOBAL 是运行时修改,MySQL 重启后失效。要持久化,必须编辑 MySQL 配置文件(如 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段落下加:
wait_timeout = 300 interactive_timeout = 300
然后重启 MySQL:sudo systemctl restart mysql(或 mysqld)。
注意:Windows 上配置文件可能是 my.ini,路径多为 C:\ProgramData\MySQL\MySQL Server X.X\。
改完务必验证:SHOW GLOBAL VARIABLES LIKE '%timeout%';,确认两个值都已更新,且应用重建连接后 @@session.wait_timeout 也同步变化。
最易忽略的一点:很多团队只调服务端参数,却忘了连接池的空闲策略和数据库驱动的 socket timeout(如 JDBC 的 socketTimeout),三者不协同,问题照旧。超时控制是端到端的事,不是改一个数字就能解决的。











