根本原因是连接池不自动检测失效连接,必须每次使用前手动调用conn.ping(reconnect=True),并捕获OperationalError异常后显式释放坏连接;SQLAlchemy需设pool_pre_ping=True,且需兼顾中间设备空闲超时。

直接结论:不是网络问题,是连接没复用、没验证、没回收——超时只是表象。
PyMySQL连接池里取出来的conn.execute()报(2013, "Lost connection to MySQL server during query")怎么办
这是最常踩的坑:以为用了PooledDB或SQLAlchemy就万事大吉,结果第一次执行 SQL 就炸。根本原因是连接池不自动检测失效连接,MySQL 已在后台断开,但池子还当它活着。
- 必须在每次使用前手动调用
conn.ping(reconnect=True),否则cursor.execute()会直接抛错 -
ping=0(DBUtils 默认)= 从不自动 ping;ping=1= 每次取连接时 ping,但失败不重连,需自己捕获异常再重试 - 别依赖
pool.connection()返回值“一定可用”,要包裹try/except pymysql.OperationalError,失败后显式调用pool.disconnect(conn)释放坏连接 - 如果用 SQLAlchemy,必须设
pool_pre_ping=True,否则pool_recycle参数无效
为什么SET GLOBAL wait_timeout=31536000执行成功却没用
这个命令只影响后续新建会话的初始值,已建立的连接和连接池里的连接仍按旧值计时。重启 MySQL 服务后,新连接才生效,但已有连接不会刷新。
- 真正生效要改配置文件(如
/etc/mysql/my.cnf),确认 MySQL 实际读的是哪个路径:mysql --help | grep "Default options" - 云数据库(如阿里云 RDS)通常禁用
SET GLOBAL,只能通过控制台修改参数模板 - 即使服务端 timeout 调高,中间设备(如 ALB、Nginx、防火墙)仍有独立空闲超时(常见 60–300 秒),它们发 FIN 包断连时,MySQL 还不知道
PyMySQL连接参数connect_timeout/read_timeout怎么设才合理
这三个 timeout 不是越大越好,设错反而掩盖真实问题:
立即学习“Python免费学习笔记(深入)”;
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
-
connect_timeout:建连阶段超时,建议 3–5 秒。设成 30 秒会让故障响应变慢,且无法区分是网络不通还是 MySQL 拒绝连接 -
read_timeout:等待查询结果返回的上限,建议 5–10 秒。长查询应优化 SQL 或分页,而不是加 timeout -
write_timeout:发送数据超时,一般 5 秒足够。写入大 BLOB 时可略调高,但需配合应用层分块上传 - 注意:这些参数对已建立连接的空闲断开(wait_timeout)完全无效,仅控制连接建立和 IO 阶段
DBUtils + PyMySQL 最小可靠配置骨架
这不是示例,是生产环境可直接抄的底线配置:
from dbutils.pooled_db import PooledDB import pymysql <p>pool = PooledDB( creator=pymysql, host='127.0.0.1', port=3306, user='root', password='xxx', database='mydb', charset='utf8mb4', autocommit=True,</p><h1>关键三超时</h1><pre class='brush:python;toolbar:false;'>connect_timeout=3, read_timeout=5, write_timeout=5, # 连接池行为 maxconnections=10, mincached=2, maxcached=5, blocking=True, ping=0, # 不自动 ping,靠业务代码手动 ping
)
每次用连接前必须写:conn.ping(reconnect=True)。漏掉这行,等于没配池子。
复杂点在于:你得在每个数据库操作入口统一加 ping 和异常兜底,而不是指望某处“配对”就自动可靠。容易被忽略的是——中间网络设备的超时比 MySQL 还短,它先断,你再怎么调wait_timeout也没用。

















