MySQL 8.0中“降级只读事务导致的锁阻塞”本质是MGR集群保护机制触发super_read_only=ON,使非PRIMARY节点不可写并抑制锁释放;若SELECT @@global.super_read_only, @@global.read_only返回1,0,且replication_group_members中MEMBER_STATE非ONLINE,则属MGR自动降级所致,需先修复节点状态再清理幽灵事务。

MySQL 8.0 中出现“降级只读事务导致的锁阻塞”,本质不是事务主动设为只读,而是 super_read_only = ON 触发的集群保护机制,它会强制所有非 PRIMARY 节点进入不可写状态,并连带抑制锁释放逻辑——比如一个在只读节点上开启但未提交的事务,可能长期持有行锁却不释放,进而阻塞其他节点的写请求。
确认是否是 MGR 降级引发的只读锁阻塞
先排除人为或配置误设:执行 SELECT @@global.super_read_only, @@global.read_only;。若返回 1, 0(即 super_read_only 为 ON、read_only 为 OFF),基本可断定是 MGR 自动施加的保护性只读,而非 DBA 手动设置。
- 此时
SHOW PROCESSLIST中可能出现大量UPDATE/INSERT线程卡在Waiting for table metadata lock或Locked,但INNODB_TRX里查不到对应活跃事务 —— 因为语句根本没进入执行阶段,被super_read_only拦在入口 - 重点查
performance_schema.replication_group_members,看本节点MEMBER_STATE是否为ERROR、UNREACHABLE或RECOVERING;只要不是ONLINE,就说明它已被集群“半隔离”,但仍在运行旧事务、持锁不放 - 别信
SHOW STATUS LIKE 'group_replication%',它可能缓存陈旧状态;information_schema.GROUP_REPLICATION_MEMBERS在节点失联未踢出时也常为空
定位仍在持锁的“幽灵事务”
即使节点处于 MEMBER_STATE = ERROR,只要它的 MySQL 进程没崩溃,之前开启的事务仍可能驻留在 INNODB_TRX 中并持有锁——这类事务不会自动回滚,也不会响应 KILL(因线程已脱离集群协调)。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 查真实持锁者:
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_started ,重点关注trx_rows_locked > 0的记录 - 关联锁详情(MySQL 8.0+):
SELECT ENGINE_TRANSACTION_ID, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS FROM performance_schema.data_locks WHERE LOCK_STATUS = 'GRANTED'; - 若发现某事务 ID 同时出现在
INNODB_TRX和data_locks中,且其trx_mysql_thread_id在PROCESSLIST里状态为Sleep或Connect,基本就是“降级后残留”的幽灵事务
安全终止降级节点上的残留锁
不能直接 KILL 线程——在 MEMBER_STATE ≠ ONLINE 时,KILL 可能无响应或触发意外回滚;应优先尝试让事务自然结束,再干预。
- 先检查该事务是否关联了长连接:查
information_schema.PROCESSLIST中对应trx_mysql_thread_id的USER、HOST、COMMAND,确认是否为应用未关闭的连接 - 若确定是僵死事务,且节点已无法回归集群,可重启 mysqld 实例(注意:这会清空所有未提交事务和内存锁);重启前务必确认该节点无写入流量、无 binlog 依赖
- 临时绕过(仅限紧急排障):在确保无其他节点依赖该实例的前提下,执行
SET GLOBAL group_replication_bootstrap_group = ON;启动单节点组,再KILL对应线程;完成后立即SET GLOBAL group_replication_bootstrap_group = OFF;并重新加入集群 - 切忌执行
SET GLOBAL super_read_only = OFF—— 这会破坏多数派共识,可能导致数据分裂或脑裂
真正棘手的从来不是锁本身,而是那个 MEMBER_STATE = RECOVERING 却迟迟不变成 ONLINE 的节点:它既不提供服务,又不释放锁,还拒绝被 KILL。这种状态下的锁排查,核心永远在“先修状态,再清锁”,而不是反过来折腾 SQL。










