mysql服务端不主动监听客户端取消,仅在读取packet时发现socket关闭或轮询mysql_killed标志时感知中断;cancel()若未关socket则服务端 unaware,而max_execution_time是唯一可靠服务端强制中断方式。

不会继续执行,但行为取决于超时类型和客户端是否真正中断了连接
MySQL 服务端如何感知客户端取消请求
MySQL 本身没有“主动监听客户端取消”的机制。它只会在两个时刻感知到异常:一是读取下一个 packet 时发现 socket 已关闭(如 Connection reset by peer);二是执行过程中检测到客户端连接已断(通过 mysql_killed 标志)。这个标志由服务端在每次语句执行的关键点(如扫描一行、写入日志前)轮询检查。
所以关键看客户端怎么“取消”:
- 如果只是应用层调用
statement.cancel()(Java)或connection.interrupt(),且底层 socket 还开着,MySQL 不会立刻知道,SQL 会照常跑完 - 如果客户端进程退出、网络中断、或显式关闭 socket(如
close()),服务端下一次尝试写回包或读新命令时会触发ERROR 2013 (HY000): Lost connection to MySQL server during query,此时正在执行的语句会被中止(前提是它支持可中断点) - 像
SELECT这类只读查询,在扫描过程中能被及时中断;但UPDATE或INSERT ... SELECT若已修改部分数据,可能已提交或回滚不完整,行为不可控
connect_timeout / wait_timeout / net_read_timeout 的区别影响
这三者都可能导致“客户端以为取消了,服务端还在跑”:
-
connect_timeout:只作用于 TCP 握手和认证阶段,超时后连接根本建不起来,不涉及 SQL 执行 -
wait_timeout和interactive_timeout:控制空闲连接存活时间,对正在执行的 SQL 无影响——哪怕你设成 1 秒,一个跑了 10 秒的SLEEP(10)也不会被杀 -
net_read_timeout:服务端等待客户端发来下一个 packet 的时间。比如客户端发完SELECT就挂了,服务端在等结果消费时超时,会断开连接并中止当前查询(但不是所有驱动都严格遵守该超时)
如何让长查询真正可取消
靠默认配置很难做到可靠取消。生产环境需要组合使用:
- 在 SQL 层加
MAX_EXECUTION_TIME=5000(MySQL 5.7.8+),这是服务端强制中断的唯一可靠方式,适用于SELECT - 应用侧设置
socketTimeout(JDBC)或read_timeout(Python mysql-connector),确保网络层真断开 - 避免在事务里执行不可分割的长操作;若必须,拆成小批次,并在每批后检查
Thread.interrupted()或类似信号 - 监控
SHOW PROCESSLIST中状态为Updating或Sending data且Time值持续增长的线程,它们很可能已脱离客户端控制
最常被忽略的一点:即使客户端显示“查询已取消”,只要没看到服务端报出 ERROR 2013 或 ERROR 2006,就无法确认 SQL 是否真的停了——得去 SHOW PROCESSLIST 里查那个线程还在不在。











