答案是服务端或中间设备主动断连,非网络故障。需检查MySQL的wait_timeout(默认8小时,云环境常缩至60~300秒)、LB空闲超时(如AWS ALB默认60秒)、max_execution_time限制,并配合conn.ping()或pool_pre_ping=True做连接保活。

OperationalError (2013, "Lost connection to MySQL server during query") 或 (2006, "MySQL server has gone away") 这类报错,不是网络真断了,而是连接被服务端或中间设备主动踢掉——脚本没做任何事时它就消失了。
MySQL服务端wait_timeout设置太短
MySQL默认wait_timeout是 28800 秒(8 小时),但很多云数据库或 Docker 镜像会改成 60~300 秒。脚本如果空闲超过这个时间,再发 query 就直接报错。
- 查当前值:
SHOW VARIABLES LIKE 'wait_timeout'; - 临时改大(需 SUPER 权限):
SET SESSION wait_timeout = 3600; - 永久生效要改
my.cnf,加[mysqld]下的wait_timeout = 3600 - 注意:
interactive_timeout控制交互式连接,也要同步调大
云环境或K8s Service自带连接超时
AWS ALB、阿里云 SLB、Kubernetes Service 默认空闲超时是 60 秒,比 MySQL 还激进。TCP 连接还在,但 LB 已经 silently 关闭了后端连接。
- 现象:用
netstat -an | grep :3306看仍是ESTABLISHED,但一发 query 就挂 - 验证方法:
tcpdump -i any port 3306 -w mysql.pcap,抓包看谁发的RST - 解决路径:在 LB 控制台把空闲超时调到 ≥ MySQL 的
wait_timeout;或让脚本主动保活
PyMySQL每次调用都新建连接,不复用也不检查
像 pymysql.connect() 这种写法,每次执行都开新连接、用完就 close,对长时运行脚本就是灾难——连接数涨、空闲连接被清、异常无重试。
- 别在循环里反复
connect+close,尤其定时任务里每 5 分钟跑一次 - 简单保活方案:用
conn.ping(reconnect=True)在执行前主动探测,失败则重建 - 更稳做法:换
SQLAlchemy+pool_pre_ping=True,它会在取连接时自动 ping - 别信“自动重连”参数:PyMySQL 的
autocommit=True或reconnect=True不可靠,只对极少数断连生效
SQL执行太久触发max_execution_time或超时中断
即使连接没空闲,一个慢查询也可能被 MySQL 主动 kill,表现为 (2013) 错误,但日志里能看到 Killed 状态。
立即学习“Python免费学习笔记(深入)”;
- 查是否被杀:
SHOW PROCESSLIST;看状态是不是Killed - 确认限制:
SELECT @@max_execution_time;(MySQL 5.7.8+) - 临时绕过:
SET SESSION max_execution_time = 0;(不推荐长期用) - 根本解法:加索引、拆大查询、设合理 timeout,避免单次操作卡住连接
conn 对象继续 execute —— 它不会提前告诉你连接死了,直到你真去发 SQL 才崩。所以 ping 和 pre-ping 不是可选项,是必须项。


















