MySQL ERROR 1205 时先找出等待者与阻塞事务,确认连接归属后安全提交、回滚或终止,并让应用完整回滚后有限重试。
MySQL 出现 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction,先不要重启数据库,也不要先把等待时间调大。这个错误通常表示当前语句需要的锁一直被另一个事务占用,等到超时仍拿不到。正确顺序是:保留报错时间和 SQL,确认等待者与阻塞者,判断阻塞事务是否还能正常提交,再由应用负责人决定提交、回滚或终止连接。
如果只想先恢复网站,默认选择是暂停产生大量写入的后台任务或导入程序,保留前台只读能力,然后处理已经确认的阻塞事务。ERROR 1205 通常只回滚发生超时的那条语句,并不保证同一事务里此前的修改全部撤销。应用收到错误后应明确回滚当前事务,再按幂等规则重试,不能把“再执行一次”写成无条件操作。
入口、费用与数据风险:自建 MySQL 从 SSH 或宝塔终端进入数据库客户端;托管数据库从云控制台进入实例的会话、性能、锁等待或诊断页面。查看锁和事务本身通常不产生额外软件费用,但托管诊断、审计、扩容或只读副本可能按平台规则收费。终止错误连接会回滚未提交事务并中断正在执行的业务;在没有确认事务所有者、影响表和回滚量前,不要执行 KILL。
先确认是锁等待,不是连接、磁盘或死锁
先完整保存错误号、发生时间、数据库名、表名、应用接口和 SQL 类型。不要在工单或群聊里粘贴含用户数据、令牌或完整业务参数的 SQL。MySQL 的几个相似问题处理方向不同:
| 现象 | 先查什么 | 默认处理 |
|---|---|---|
ERROR 1205 / Lock wait timeout | 谁在等待、谁持有锁、事务从何时开始 | 缩短或结束已确认的阻塞事务,再回滚并重试失败事务 |
ERROR 1213 / Deadlock found | 最近死锁图、两边加锁顺序 | 应用重试被回滚事务,并统一访问顺序 |
| Waiting for table metadata lock | 未提交事务、DDL、备份或表结构变更 | 先处理持有元数据锁的会话,不盲目增加 InnoDB 行锁等待时间 |
| Too many connections | 连接数、连接池和空闲连接 | 按连接耗尽处理,不把它归为锁超时 |
站内已有 MySQL Too many connections 排查 和 MySQL 慢查询排查。本文只处理事务锁等待,不重复解释连接上限或一般执行计划优化。
第一步:只读确认版本、超时参数和当前事务
以下 SQL 只读取状态,适合 MySQL 8.0/8.4。需要具有查看其他会话和 Performance Schema 的相应权限。托管数据库权限受限时,优先使用控制台的会话或锁等待页面,不要为了运行查询给网站账号增加管理员权限。
SELECT VERSION();
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
SELECT
trx_id,
trx_state,
trx_started,
trx_mysql_thread_id,
LEFT(trx_query, 200) AS current_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
重点看事务开始时间,不只看当前 SQL。一个连接可能显示为空闲,但仍留着未提交事务并持有锁。查询内容可能包含业务数据,截图前要遮挡参数。没有看到事务不代表错误不存在:阻塞事务可能已经结束,也可能问题发生在另一台数据库或读写节点。
第二步:找出等待者与阻塞者
MySQL 的 sys.innodb_lock_waits 会把等待事务、阻塞事务、表、索引和连接 ID 汇总在一起。先执行只读查询并保存证据:
SELECT
wait_age_secs,
locked_table_schema,
locked_table_name,
locked_index,
waiting_pid,
LEFT(waiting_query, 200) AS waiting_query,
blocking_pid,
LEFT(blocking_query, 200) AS blocking_query
FROM sys.innodb_lock_waits
ORDER BY wait_age_secs DESC;
waiting_pid 是正在等锁的连接,blocking_pid 才是当前阻塞它的连接。不要把两者看反。blocking_query 为空并不代表没有阻塞:持锁连接可能已经执行完一条语句,却没有提交或回滚。
如果实例没有可用的 sys 视图,可在 MySQL 8.0/8.4 使用 Performance Schema 的 data_lock_waits 继续取证;不同版本字段和视图可能不同,先核对版本官方文档。不要把旧版 information_schema.innodb_locks 查询直接复制到所有实例。
SELECT
REQUESTING_ENGINE_TRANSACTION_ID AS waiting_trx,
BLOCKING_ENGINE_TRANSACTION_ID AS blocking_trx,
REQUESTING_THREAD_ID AS waiting_thread,
BLOCKING_THREAD_ID AS blocking_thread
FROM performance_schema.data_lock_waits;
这一层先证明存在等待关系,再回到 information_schema.innodb_trx 和应用日志确认连接来自哪个服务、任务或人工操作。仅凭一个连接 ID 不能判断可以安全终止。
第三步:判断阻塞事务该提交、回滚还是保留
先联系事务所有者或应用负责人,核对以下信息:连接来自前台请求、定时任务、导入、后台编辑还是迁移;事务是否正在提交大批修改;应用是否有自动重试;终止后回滚需要多久;主从复制或集群是否处于异常状态。
- 人工窗口忘记提交:回到原会话核对修改,明确执行
COMMIT或ROLLBACK。不要另开窗口猜测。 - 后台任务单次事务过大:先暂停新任务;允许当前事务在维护窗口完成,或由负责人评估回滚。后续把任务拆成可提交的小批次。
- 网站请求持锁等待外部接口:应用应缩短事务范围,把网络请求、文件处理和人工确认移到事务之外。
- 表结构变更排队:若进程状态显示元数据锁等待,应先识别持有旧表定义的事务。调整
innodb_lock_wait_timeout未必解决元数据锁。 - 托管数据库:用控制台会话管理功能确认账号、来源和持续时间;权限不足时提交给实例管理员,不要把网站账号升为高权限账号。
需要止损时,怎样安全终止连接
只有在连接归属、事务影响和回滚窗口已经确认后才考虑终止。先再次核对连接 ID,防止连接结束后 ID 被复用。KILL QUERY 只停止当前语句,连接和事务状态仍需应用处理;KILL CONNECTION 会断开连接并触发未提交事务回滚,回滚可能持续占用 I/O 和锁。
-- 把 12345 替换为刚刚复核的实际连接 ID
KILL QUERY 12345;
-- 只有确认需要断开整个连接时才执行
KILL CONNECTION 12345;
执行后不要立刻重启 MySQL,也不要删除 InnoDB 文件。持续查看事务列表、错误日志和磁盘 I/O,等回滚完成。大事务回滚期间强制重启可能让恢复时间更长,还会扩大业务中断。
应用收到 ERROR 1205 后怎样处理
MySQL 官方错误说明强调,锁等待超时时通常回滚的是等待语句,而不是自动回滚整个事务。应用应捕获错误,明确回滚当前事务,释放它已经持有的锁,再决定是否重试。重试必须满足幂等条件,并使用有限次数和退避,避免多个请求同时重试形成新的锁风暴。
开始事务
执行业务 SQL
如果出现 ERROR 1205:
回滚整个当前事务
记录请求标识和冲突对象
在幂等条件成立时,延迟后有限重试
成功后提交
支付、库存、余额或消息投递不能仅靠“再试一次”。要用唯一业务键、条件更新或去重表保护重复执行。WordPress、队列消费者和批量导入工具若不暴露事务边界,应先暂停相关插件或任务,并通过数据库与应用日志共同确认。
为什么不建议先调大 innodb_lock_wait_timeout
把等待时间调大只能让语句等得更久,不能释放阻塞锁。短事务偶尔被长事务挡住时,提高参数可能把错误变成更长的页面卡顿和更多堆积连接。默认先修事务范围、索引、访问顺序和连接池释放。
若经过压测确认业务确实需要更长等待,可先只在受控会话中临时调整并观察,不直接全局修改。参数单位和作用范围以当前版本官方文档为准:
-- 示例只影响当前会话;60 需要按已验证的业务窗口替换
SET SESSION innodb_lock_wait_timeout = 60;
SHOW SESSION VARIABLES LIKE 'innodb_lock_wait_timeout';
调整前记录原值,测试完成后断开测试会话或恢复原值。死锁由检测机制处理,并不会因为单纯调大行锁等待时间而消失。
怎样从根因上减少锁等待
- 让事务只包含必须原子完成的数据库操作,不在事务里等待 HTTP、文件上传或人工操作。
- 为筛选和更新条件建立经过执行计划验证的索引,避免扫描并锁住远超预期的记录。
- 多个业务流程以相同顺序访问表和行,减少交叉等待。
- 批量更新、导入和删除分成可恢复的小批次,每批提交后记录进度。
- 连接池归还连接前明确提交或回滚,禁止把带未完成事务的连接交给下一个请求。
- 为锁等待时间、长事务数和后台任务耗时建立告警,不能只等用户看到 500 页面。
如果根因是慢 SQL,可继续参考 慢日志、执行计划与索引验证;如果应用已经连接不上,则先按 MySQL ERROR 2002 的服务、Socket 与 TCP 分支恢复入口。
修复后怎样验收,失败时怎样回退
- 确认
sys.innodb_lock_waits中原等待关系已消失,长事务数量回到正常范围。 - 用一条可回滚、影响范围小的同类写入验证,不直接重放整批生产任务。
- 确认应用错误率、接口耗时、连接池占用和数据库 I/O 没有继续上升。
- 确认发生 1205 的事务已经完整回滚或按业务规则重新执行,没有重复扣减、漏更新或半完成状态。
- 在下一次业务高峰和定时任务窗口复查,不以一次成功代替持续验收。
如果终止连接后回滚持续很久,停止继续终止更多会话,保留数据库日志和事务快照,联系数据库负责人评估。若临时改过会话或全局参数,恢复原值;若发布了应用事务改动,使用原版本和数据库备份验证回退,但不要在未确认数据状态时直接覆盖生产库。
官方资料
- MySQL 8.4 Server Error Message Reference:核对 ERROR 1205 与 ERROR 1213 的含义和回滚边界。
- MySQL sys.innodb_lock_waits:核对等待事务、阻塞事务和连接字段。
- MySQL Performance Schema data_lock_waits:核对 MySQL 8.0/8.4 的锁等待关系。
- MySQL innodb_lock_wait_timeout:核对参数范围、动态修改与适用边界。

