connectionreseterror 通常是数据库服务端因查询超时(如 wait_timeout)主动断连所致,并非网络故障;应检查查询性能或调整服务端超时配置,而非排查防火墙。

ConnectionResetError 是超时的间接表现,不是网络断开本身
看到 ConnectionResetError: [Errno 104] Connection reset by peer 别急着查防火墙或重装驱动。这通常是数据库服务端在连接建立后、查询执行中主动中断了连接——根本原因往往是查询执行时间超过了服务端设置的 wait_timeout(MySQL)或 remote query timeout(SQL Server),触发了强制断连。客户端收到的只是“连接被重置”这个结果,而非原始超时信号。
验证方式很简单:用相同 SQL 在命令行工具(如 mysql -h ... -e "SELECT ..." 或 SSMS)里手动执行,看是否卡住或报 Query execution was interrupted 类错误。如果会,那问题就锁定在查询本身或服务端超时配置上。
长查询必须拆分,但不能简单按 LIMIT OFFSET 硬切
对千万级表做 SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at LIMIT 1000 OFFSET 500000 这类语句,OFFSET 越大性能越差,甚至可能锁表或拖垮缓冲池。这不是超时“能不能忍”的问题,而是数据库底层扫描成本指数级上升。
真正可行的拆分逻辑是基于**游标(cursor-based pagination)**:
- 第一次查:
SELECT id, order_no, amount FROM orders WHERE status = 'pending' ORDER BY id ASC LIMIT 1000 - 记住返回结果中最大的
id(比如last_id = 123456) - 下一批查:
SELECT id, order_no, amount FROM orders WHERE status = 'pending' AND id > 123456 ORDER BY id ASC LIMIT 1000
关键点:id 必须有索引;WHERE 条件里的字段(如 status)也要参与联合索引;避免 ORDER BY RAND() 或函数包裹字段(如 DATE(created_at)),否则游标失效。
批量写入别用单条 INSERT,但 bulk insert 也有隐性超时
用 ORM 的 bulk_create() 或原生 INSERT INTO ... VALUES (...), (...), (...) 是正确方向,但要注意两点:
一是单次批量不宜过大。MySQL 默认 max_allowed_packet 是 4MB,SQL Server 对单条语句长度也有硬限制。超过就会直接报错,而不是超时。建议单批控制在 1000–5000 行,视单行数据大小动态调整。
二是即使语句合法,执行时间仍可能超服务端 max_execution_time(MySQL 5.7+)或 query wait(SQL Server)。所以更稳妥的做法是:在循环中分批提交,并为每批加独立超时控制:
for batch in chunked_data:
try:
cursor.executemany("INSERT INTO logs (...) VALUES (...)", batch)
conn.commit()
except OperationalError as e:
if "timeout" in str(e).lower():
log.warning(f"Batch of {len(batch)} rows timed out, retrying with half size")
split_and_retry(batch) # 递归减半再试
else:
raise
这种“失败即降级”的策略比全局设长超时更可控,也避免单个慢批拖垮整组任务。
超时参数要分层设,且客户端和服务端必须协同
只改客户端 connect_timeout=60 没用——如果服务端 wait_timeout=30,连接建好 30 秒没发查询也会被杀。必须两端对齐:
- MySQL:客户端设
connect_timeout和read_timeout;服务端调wait_timeout(非交互式连接)和interactive_timeout(交互式) - SQL Server:连接字符串加
Connect Timeout=60;服务端需确认remote query timeout(sp_configure)未设为 0(无限)或过小 - PostgreSQL:客户端用
options='-c statement_timeout=30000';服务端设statement_timeout参数
最易忽略的一点:ORM 框架(如 Django、SQLAlchemy)常自带默认超时,可能覆盖你显式传入的参数。例如 SQLAlchemy 的 create_engine(..., connect_args={"timeout": 10}) 只影响连接建立,不控制查询执行;查询级超时得靠 execution_options(timeout=30) 单独指定。










