在mysql运行中,元数据锁(Metadata Lock,简称MDL)用于保证表结构在并发访问时的一致性。当某条SQL出现长时间挂起,很可能就是被MDL等待阻塞。理解其产生原因并掌握定位方法,对保障数据库稳定非常关键。

什么是元数据锁
元数据锁是mysql在访问表时自动加上的锁,分为读锁和写锁。读锁之间兼容,但写锁与任何锁都互斥。通常select会加MDL读锁,alter table等DDL会加MDL写锁。如果某会话长时间持有MDL读锁不释放,后续DDL就会等待写锁,进而阻塞其他所有访问该表的SQL。
如何定位MDL等待
在mysql 5.7及以上版本,可以通过performance_schema下的元数据锁相关视图来观察。主要使用<code>metadata_locks</code>视图和<code>threads</code>视图关联查询。
-- 查看当前存在的元数据锁及持有线程 SELECT t.PROCESSLIST_ID AS conn_id, t.PROCESSLIST_USER AS user, t.PROCESSLIST_HOST AS host, ml.OBJECT_SCHEMA AS db_name, ml.OBJECT_NAME AS table_name, ml.LOCK_TYPE AS lock_type, ml.LOCK_STATUS AS lock_status FROM performance_schema.metadata_locks ml JOIN performance_schema.threads t ON ml.OWNER_THREAD_ID = t.THREAD_ID WHERE ml.OBJECT_TYPE = 'TABLE';
若看到某行LOCK_STATUS为PENDING,说明该会话正在等待MDL。同时可结合<code>processlist</code>或<code>events_statements_current</code>找到阻塞源头。
通过processlist辅助分析
-- 查看活跃会话及执行语句 SHOW PROCESSLIST;
重点关注Command为Sleep但Time很大的会话,这类长空闲事务往往持有MDL读锁未提交。
Metadata Lock常见产生原因
- 未提交的长事务:事务中执行了select后未commit,一直持有MDL读锁。
- 线上直接执行DDL:在业务高峰期对大表执行alter table,被已有读锁阻塞。
- 显式开启事务后忘记关闭:程序异常退出但连接未释放。
- 备份工具或监控语句频繁访问表结构。
排查与解决思路
步骤一:找到阻塞源
利用上面metadata_locks查询,找出LOCK_STATUS为GRANTED且锁类型与PENDING冲突的线程ID。
步骤二:确认业务影响
若阻塞源是闲置事务,可与业务确认后执行KILL CONNECTION对应ID,释放MDL。
-- 杀掉持有锁的连接,请确认业务允许 KILL 12345;
步骤三:规范DDL操作
将表结构变更放到低峰期,或使用支持online ddl的工具,减少MDL写锁持有时间。
注意:mysql 8.0中metadata_locks默认未开启采集,需在配置中设置performance-schema-instrument='wait/lock/metadata/sql/mdl=ON'。
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| SQL卡住无报错 | MDL写锁等待 | 查metadata_locks找源头 |
| alter table不动 | 有长事务持读锁 | 提交或Kill事务 |
| 连接数上涨 | 大量会话等MDL | 优先解阻塞源 |
掌握上述方法后,面对mysql中的元数据锁等待问题,就能快速定位并排查Metadata Lock的产生原因,降低对线上业务的影响。
mysqlMetadata_Lock锁等待排查修改时间:2026-07-25 18:33:26