mysql gone away 错误本质是服务端主动断连,主因是wait_timeout超时或max_allowed_packet过小;需对齐服务端配置与客户端连接池探活机制,而非修改业务逻辑。

MySQL gone away 错误本质是连接断开,不是程序 bug
这个错误(MySQL server has gone away)多数时候不是代码写错了,而是服务端主动切断了连接。常见触发点就两个:超时断连、单包超限。别急着改业务逻辑,先看配置是否合理。
wait_timeout 和 interactive_timeout 必须对齐应用行为
MySQL 用这两个参数控制空闲连接存活时间:wait_timeout 用于普通连接,interactive_timeout 用于带 CLIENT_INTERACTIVE 标志的连接(比如 MySQL CLI)。但 Python 的 pymysql、Go 的 database/sql 默认不设该标志,所以实际生效的是 wait_timeout。
- 查当前值:
SHOW VARIABLES LIKE '%timeout%'; - 若应用连接池长期空闲(比如 Web 服务低峰期),
wait_timeout设为 28800(8 小时)往往太高,建议调到 300–600(5–10 分钟)更稳妥 - 客户端无需同步改 timeout,但连接池必须支持「连接有效性检测」:比如
mysql.connector要开pool_reset_session=True,sqlalchemy推荐配pool_pre_ping=True - 注意:改完
my.cnf后需重启 MySQL 或用SET GLOBAL wait_timeout = 600;(仅当前会话有效)
max_allowed_packet 太小会导致大 INSERT/LOAD 中断
当执行 INSERT ... VALUES (...), (...), (...) 或 LOAD DATA INFILE 时,整条语句被打包成一个网络包发送。如果总长度超过 max_allowed_packet,服务端直接断连并报 gone away,而不是返回语法错误。
- 默认值通常是 4MB(
4194304),但批量插入上万行 JSON 字段很容易超 - 查当前值:
SHOW VARIABLES LIKE 'max_allowed_packet'; - 客户端也要匹配:PHP 的
mysqli需设mysqli_options($link, MYSQLI_OPT_MAX_ALLOWED_PACKET, 64*1024*1024);Python 的pymysql在 connect 时加max_allowed_packet=67108864 - 别只调服务端——如果客户端发包前就因内存限制截断了数据,服务端根本收不到完整包
连接池没做失效检测,会让“已断”连接继续复用
很多框架或自建池子默认不验证连接状态,拿到一个上次用过的连接就直接发 query。而此时连接可能已在服务端超时关闭,第一次 query 就触发 gone away。
- Java HikariCP 默认开启
connection-test-query=SELECT 1(需配connection-test-query+validation-timeout) - Node.js
mysql2池要手动在 query 前加connection.ping(),或用enableKeepAlive: true+keepAliveInitialDelay: 0 - 最轻量方案:所有执行前加一句
SELECT 1,但要注意增加 RT;更推荐用pool_pre_ping类机制,在取连接时做一次探活 - 注意:MySQL 8.0+ 的
auto-reconnect已被移除,别依赖它
超时和包大小不是孤立参数,它们和你的连接复用方式、SQL 构造习惯、客户端驱动版本都咬合在一起。改一个值之前,先确认它在哪一环真正起作用。










