mysql报错2013多因服务端主动断连,首查max_allowed_packet是否过小,次查net_read/write_timeout是否超时,再检客户端保活机制。

这个报错不是“连接失败”,而是查询执行到一半时连接突然断了——90% 的 case 根本不怪网络,是服务端主动掐断的。先查 max_allowed_packet,再看超时参数,别一上来就调 wait_timeout。
确认是不是 max_allowed_packet 太小
服务端收到或要发的数据包超过限制,会静默断连,不报具体原因。这是最常被忽略的第一环。
- 连上 MySQL 执行:
SELECT @@global.max_allowed_packet, @@session.max_allowed_packet;—— 如果返回4194304(即 4MB),而你正插入大 JSON、导出含 BLOB 的表、或用mysqldump备份,基本就是它了 -
SET SESSION max_allowed_packet = 67108864只对当前会话有效;SET GLOBAL需要管理员权限,且在阿里云 RDS、AWS RDS 等托管服务上通常禁止 - 永久生效必须改配置文件:在
[mysqld]段加max_allowed_packet = 64M(注意单位后缀,不能写64*1024*1024),然后sudo systemctl restart mysql - 客户端工具也得同步:比如
mysqldump --max-allowed-packet=64M、mysql --max-allowed-packet=64M,PyMySQL 连接 URL 里也要显式带max_allowed_packet=67108864
检查 net_read_timeout 和 net_write_timeout
这两个参数控制服务器读/写一个数据包的等待上限,和 wait_timeout 完全不同。大查询卡在传输中间时,它们比空闲超时更早触发断连。
- 执行:
SHOW VARIABLES LIKE 'net%timeout';—— 默认值通常是 30 秒,对复杂 JOIN 或大数据集远远不够 - 临时调高(需 SUPER 权限):
SET GLOBAL net_read_timeout = 600;、SET GLOBAL net_write_timeout = 600; - 永久修改同样加进
[mysqld]段:net_read_timeout = 600、net_write_timeout = 600,再重启 - 注意:设太高可能掩盖慢查询问题,建议结合
EXPLAIN先确认 SQL 本身是否合理
客户端驱动和连接池没做保活
很多框架(如 SQLAlchemy + PyMySQL、Django DB)默认不验证连接有效性,拿到一个已断开的连接就直接发 query,报错就是 2013。
- SQLAlchemy 示例:在
create_engine中加参数pool_pre_ping=True,每次取连接前先发个PING - PyMySQL 连接字符串加
autocommit=True和read_timeout=600、write_timeout=600,避免驱动层自己超时 - Navicat / MySQL Workbench:在 Preferences → SQL Editor → DBMS connection keep-alive interval 设为 300(秒),但仅对新连接生效
- 如果用连接池(如 HikariCP),务必开启
connection-test-query或等效健康检查,否则空闲连接过期后仍会被分配出去
真正麻烦的是:同一个 2013 报错,可能是 max_allowed_packet 不够、net_write_timeout 触发、防火墙主动 kill 长连接、甚至 mysqld 进程被 OOM Killer 干掉——四者日志表现几乎一样。优先按顺序查这三项,别跳步。配置改完一定要验证:SELECT @@global.max_allowed_packet;、SHOW VARIABLES LIKE 'net%timeout';,别只信重启了。











