答案是先查max_allowed_packet和net_read_timeout参数。该报错90%源于服务端主动断连,非网络问题;首查max_allowed_packet是否过小导致静默断连,次查net_read_timeout/net_write_timeout是否超时,再检客户端保活及服务器资源瓶颈。

这不是网络断开,而是MySQL服务端主动掐断了正在执行的查询连接——90% 的 case 根本不用查路由器或防火墙,先看 max_allowed_packet 和 net_read_timeout。
查 max_allowed_packet 是不是太小
服务端收到或要返回的数据包超过限制时,会静默断连,不报具体错误。大 JSON、BLOB 字段、mysqldump 导出、SELECT 返回百万行,都容易踩这个坑。
- 连上 MySQL 执行:
SELECT @@global.max_allowed_packet, @@session.max_allowed_packet;—— 如果是4194304(4MB),而你正在处理大结果集,基本就是它 -
SET SESSION max_allowed_packet = 67108864只对当前会话生效;SET GLOBAL需 SUPER 权限,且在阿里云 RDS、AWS RDS 上通常禁止 - 永久生效必须改配置文件:在
[mysqld]段加max_allowed_packet = 64M(注意单位后缀,不能写64*1024*1024),然后重启 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 完全不同。复杂 JOIN、流式返回大数据时,它们比空闲超时更早触发断连。
- 默认值通常是 30 秒,对大查询远远不够;执行
SHOW VARIABLES LIKE 'net_%_timeout';查当前值 - 临时调高(需 SUPER 权限):
SET GLOBAL net_read_timeout = 600;、SET GLOBAL net_write_timeout = 600; - 永久修改同样加进
[mysqld]段:net_read_timeout = 600、net_write_timeout = 600,再重启 - 设太高可能掩盖慢查询问题——建议先用
EXPLAIN确认 SQL 本身是否合理,别只调参
检查客户端连接池有没有保活机制
很多框架默认不验证连接有效性,拿到已断开的连接就直接发 query,报错就是 2013。
- SQLAlchemy:在
create_engine中加参数pool_pre_ping=True,每次取连接前先发 PING - PyMySQL:连接字符串加
read_timeout=600、write_timeout=600,避免驱动层自己超时;autocommit=True也能减少事务挂起风险 - Navicat / MySQL Workbench:Preferences → SQL Editor → DBMS connection keep-alive interval 设为
300(秒),但仅对新连接生效 - 如果用 HikariCP 等连接池,务必开启
connection-test-query或等效健康检查配置
别漏掉服务器资源瓶颈这个隐性原因
CPU 满载、OOM Killer 杀进程、磁盘 IO 堵塞、临时表空间不足,都会导致查询中途被强制中断,现象和超时一模一样。
- 查 OOM 记录:
dmesg | grep -i "out of memory"、dmesg | grep -i mysql - 查磁盘空间:
df -h;查 MySQL 错误日志:tail -f /var/log/mysql/error.log - 查当前负载:
top或htop看 CPU、内存、IO wait;SHOW PROCESSLIST看是否有长时间Sleep或Locked的连接 - 如果发现某条 SQL 占用大量 CPU,优先优化它——建联合索引、加
LIMIT、拆分查询,比调 timeout 更治本
真正麻烦的不是参数调多少,而是多个条件叠加:比如 max_allowed_packet 刚好卡在临界值,net_read_timeout 又没调够,再加上客户端连接池没保活——这时候单改一个地方根本压不住报错。


















