ALTER TABLE卡住主因是元数据锁(MDL)阻塞或tmpdir磁盘满:前者由未提交事务持有MDL读锁导致,需查INNODB_TRX定位并谨慎终止;后者因ALTER重建表大量用临时文件,需检查并扩容tmpdir。

ALTER TABLE 卡住不动,SHOW PROCESSLIST 显示 Waiting for table metadata lock
这是典型的元数据锁(MDL)阻塞,不是磁盘满导致的,但两者常被同时排查。MySQL 在执行 ALTER TABLE 时会申请 MDL 写锁,而只要有一个长事务(哪怕只是 SELECT)没提交,就卡住后续 DDL。
- 立刻查
SHOW PROCESSLIST,找State为Waiting for table metadata lock的线程,记下它的ID - 再查
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5;,比对TRX_MYSQL_THREAD_ID找出未提交事务的源头 - 重点看
TRX_QUERY是否为空(空表示事务已开始但还没执行语句),以及TRX_STARTED时间是否异常久 - 不要直接 kill 大事务,先确认业务影响;若必须终止,用
KILL [thread_id],不是KILL QUERY
ERROR 1034 (HY000): Incorrect key file for table,磁盘空间其实够但报错
这个错误表面像索引文件损坏,实际常因临时目录(tmpdir)所在分区爆满触发——ALTER TABLE 重建表时大量使用临时文件,而 tmpdir 默认可能在 /tmp,和 MySQL 数据目录不在同一磁盘。
- 查当前设置:
SELECT @@tmpdir;,再用df -h看对应路径剩余空间 - 临时解决:改
tmpdir到空间充足的挂载点,比如SET GLOBAL tmpdir = '/data/tmp';(需确保目录存在且 MySQL 进程有读写权限) - 永久生效:在
my.cnf的[mysqld]段加tmpdir = /data/tmp,重启前确认该路径不被 SELinux 或 AppArmor 拦截 - 注意:修改后新连接才生效,已有连接仍用旧
tmpdir
ALTER TABLE 修改列类型失败,提示 Lost connection to server during query
这不是网络问题,而是大表 DDL 过程中内存或超时被强制中断。尤其当涉及字符集转换(如 utf8mb4)、全文索引重建、或在线 DDL 不支持的操作时,MySQL 可能回退到拷表模式,期间资源消耗陡增。
- 检查错误日志里是否有
Out of memory或Aborted connection相关记录 - 调大关键参数:临时增加
innodb_buffer_pool_size(别超物理内存 75%),并设lock_wait_timeout=3600避免中途超时 - 生产环境优先用
ALGORITHM=INPLACE, LOCK=NONE显式指定(需 MySQL 5.6+ 且操作支持),例如:ALTER TABLE t MODIFY c VARCHAR(200) CHARACTER SET utf8mb4, ALGORITHM=INPLACE, LOCK=NONE; - 如果表太大(>10GB),别硬扛,拆成两步:先加新列、同步数据、再删旧列,用应用层灰度
为什么 FLUSH TABLES WITH READ LOCK 后 ALTER TABLE 还卡住
加全局读锁确实能避免 DML 干扰,但无法绕过元数据锁等待逻辑——如果此时已有活跃事务持有 MDL 读锁(比如一个慢 SELECT 正在扫全表),ALTER TABLE 仍会等它释放。
-
FLUSH TABLES WITH READ LOCK只阻塞新 DML,不杀已有事务,也不释放它们持有的 MDL - 执行前务必确认
information_schema.INNODB_TRX为空,否则锁只是“假安静” - 真正安全的操作顺序是:停写入 → 查无活跃事务 →
FLUSH TABLES WITH READ LOCK→ALTER TABLE→UNLOCK TABLES - 注意:主从架构下,该命令会阻塞从库 SQL 线程,慎用于线上主库
事情说清了就结束。最常漏掉的是:以为磁盘够就万事大吉,结果 tmpdir 独立挂载点早满了;或者 kill 了 DDL 线程,却忘了它背后可能挂着一个没提交的事务,下次照样卡。


















