是,客户端断开后mysql仍执行查询属正常设计:服务端不感知tcp断连,仅当写回结果失败或被显式kill时才终止;wait_timeout仅作用于空闲连接,不影响活跃查询。

客户端断开后MySQL仍在执行查询,是正常行为
这不是 bug,而是 MySQL 的设计逻辑:客户端关闭连接(比如因 socketTimeout 或网络中断)只终止 TCP 连接,服务端不会自动中止正在运行的语句。MySQL 服务端并不感知“客户端已走”,它只按自身调度继续执行,直到完成、超时或被显式 kill。
wait_timeout 不影响正在执行的查询
wait_timeout 只作用于空闲连接——即没有 SQL 正在执行、也没有 pending 请求的状态。一旦客户端发来一条 SELECT 或 UPDATE,该连接就进入“活跃”状态,wait_timeout 计时暂停。所以即使你设了 30 秒,一个跑 5 分钟的慢查询也不会被它打断。
- 真正可能中断它的参数是
max_execution_time(需 MySQL 5.7+,且语句级显式启用) - 或者
innodb_lock_wait_timeout(只针对锁等待,不是执行本身) - 服务端 OOM、崩溃、手动
KILL QUERY才会强制终止
常见误判场景:你以为断了,其实没断
很多“客户端报错 Connection reset / Lost connection”发生时,其实是 TCP 层断开(比如中间 Nginx 的 proxy_read_timeout 到期),但服务端根本不知道,还在刷 binlog、写 redo、等锁、甚至把结果集缓存到 net_buffer 中——直到它尝试往 socket 写回结果时才发现 write failed,才真正清理资源。
- 这种延迟释放会导致
SHOW PROCESSLIST里看到Query状态持续几十秒甚至更久 - 如果该查询持有行锁或表锁,其他事务会被卡住,引发连锁阻塞
- 用
SHOW ENGINE INNODB STATUS\G查TRANSACTIONS部分,能看到未提交事务和锁信息
如何避免查询“无人收场”
不能依赖客户端断连来终止服务端任务,必须主动控制:
- 应用层设置语句级超时:PyMySQL 支持
timeout参数;JDBC 用statement.setQueryTimeout() - 服务端全局开启
max_execution_time(如SET GLOBAL max_execution_time = 30000),对所有 SELECT 生效(注意:INSERT/UPDATE 不受控) - 监控
INFORMATION_SCHEMA.PROCESSLIST,对运行超过阈值的Command=Query主动KILL - 避免在长事务里做大量计算或循环——把大任务拆成小批次,每批后 commit 并检查连接健康
最易被忽略的是:你 kill 掉一个连接(KILL CONNECTION xxx),MySQL 会立即中断其当前语句并回滚事务;但如果你只是关掉应用进程或网络断开,服务端不会立刻响应,它得等到下次写操作失败才清理。这个时间差就是“查询还在跑”的根源。











