mysql 8.0 连接频繁断开的根源是服务端 wait_timeout=28800 秒(8 小时)过长,导致空闲连接被服务端主动断开而连接池未感知;须将 wait_timeout 和 interactive_timeout 同步调低至 600 秒(10 分钟),并重启 mysqld,同时 hikaricp 的 maxlifetime 设为 540000 毫秒(9 分钟)以预留 60 秒缓冲,再配合 idletimeout=300000 毫秒及连接有效性验证确保连接及时回收。

MySQL 8.0 的 wait_timeout 和 interactive_timeout 必须先调低
连接池“死连接”堆积的根源,往往不是池子本身,而是 MySQL 服务端默认 wait_timeout=28800(8 小时)太长,导致空闲连接长期挂在那里不释放。应用层连接池却误以为连接还活着,反复复用——结果一执行 SQL 就报 MySQL server has gone away。
必须改这两个参数:
-
wait_timeout = 600:控制非交互式连接(即你 Java/Python 应用连的)空闲 10 分钟就断开 -
interactive_timeout = 600:命令行、Navicat 等工具也统一按 10 分钟清理,避免开发连着不关拖累全局
改完必须重启 MySQL:systemctl restart mysqld(Linux)或 net stop mysql && net start mysql(Windows)。只 SET GLOBAL 不持久,且已存在的连接不会立即受新值影响。
HikariCP 的 maxLifetime 必须比 wait_timeout 小至少 60 秒
光靠 MySQL 断连接不够——连接池不知道连接已被 kill,还会继续分配给你。所以池子自己得“主动退休”。
假设你设了 wait_timeout = 600(10 分钟),HikariCP 的 maxLifetime 就不能设成 600000 毫秒(等于 10 分钟),而应设为:
-
maxLifetime = 540000(9 分钟),留出 60 秒缓冲 - 同时配
idleTimeout = 300000(5 分钟),确保空闲连接更早被回收 - 禁用
connection-test-query(HikariCP 已弃用),改用connection-init-sql=SELECT 1或开启pool-pre-ping=true(SQLAlchemy)做轻量心跳
别信 testOnBorrow:每次取连接都查一次库,压测时直接拖垮性能。
connect_timeout 和 socketTimeout 必须协同配置
connect_timeout 是 MySQL 服务端参数,控制 TCP 握手+认证阶段最长等多久;它只读,不能 SET GLOBAL,只能写进 /etc/my.cnf 的 [mysqld] 段并重启:
-
connect_timeout = 10:防慢速攻击,避免无效连接占满线程
而客户端的 socketTimeout(JDBC)或 read_timeout(PyMySQL)才是控制“SQL 执行中网络卡住多久就放弃”的关键:
- JDBC 连接串加
&socketTimeout=600000(10 分钟),要大于你最长查询预期 - PyMySQL 初始化时传
read_timeout=60, write_timeout=60,否则大结果集返回中途断连无感知
漏掉这个,就算 MySQL 连接没断,客户端也会在读响应时抛 The last packet successfully received...。
验证是否真生效,不能只看配置文件
改完不验证 = 白改。必须连上 MySQL 执行这两条命令:
-
SHOW GLOBAL VARIABLES LIKE '%timeout%';——确认wait_timeout、interactive_timeout、connect_timeout是你设的值 -
SHOW PROCESSLIST;——重点看State列,大量Sleep且Time超过 600 秒的连接,说明配置没生效或没重启
特别注意:connect_timeout 在 SHOW GLOBAL VARIABLES 里一定存在,但它是只读的——如果这里显示的不是你配的值,说明配置文件路径错了、段落写成 [client] 了,或者根本没重启服务。











