repair table仅适用于myisam表,innodb执行会报error 1031;非法关机后mysql系统库中user、host等myisam表易损坏,须停服务后用myisamchk离线修复,innodb则依赖崩溃恢复而非修复。

不能直接用 REPAIR TABLE 修所有表——它只对 MyISAM 有效,InnoDB 表执行会报 ERROR 1031;非法关机后最先出问题的往往是 mysql 系统库里的 user、host、plugin 这类 MyISAM 表,得优先离线修复。
先确认损坏的是什么表、什么引擎
非法关机后 MySQL 启动失败或登录报错,错误日志里常出现类似 Table './mysql/user' is marked as crashed 或 Can't open and lock privilege tables。这类提示基本锁定在 mysql 库的 MyISAM 表上(user、db、host、tables_priv 等)。
别急着修,先验证:
- 查引擎:
SHOW CREATE TABLE mysql.user;—— 看ENGINE=MyISAM还是InnoDB;MySQL 5.7 及以前默认是 MyISAM,8.0+ 系统表已转 InnoDB,但老实例或手动改过的仍可能是 MyISAM - 看状态:
SHOW TABLE STATUS FROM mysql LIKE 'user';—— 如果Comment列显示Crashed,就是它了 - 别信
CHECK TABLE:系统表损坏严重时,这条命令本身可能卡死或报权限错误,不如直接看日志
MyISAM 权限表损坏:必须停服务 + myisamchk 离线修复
REPAIR TABLE 在 MySQL 进程里跑不了——因为权限表损坏会导致 mysqld 根本启不来,连连接都建立不了。这时只能切到 shell,用 myisamchk 直接操作文件。
步骤很明确:
- 确保 mysqld 已停止:
sudo systemctl stop mysql(或service mysqld stop) - 定位数据目录和表文件:通常为
/var/lib/mysql/mysql/user.MYI(路径以你实际datadir为准) - 先校验不修改:
myisamchk -s /var/lib/mysql/mysql/user.MYI—— 看输出是否含is not closed或record delete-link - 再强制修复:
myisamchk -r -f /var/lib/mysql/mysql/user.MYI(-f强制覆盖损坏索引) - 如果报
Key block size is wrong,换更激进方式:myisamchk --safe-recover -f /var/lib/mysql/mysql/user.MYI
修完一个,顺手把 host、db、tables_priv 都过一遍,别漏——它们常连锁损坏。
InnoDB 表启动失败:不是“修”,而是让崩溃恢复生效
如果你发现错误日志里有 InnoDB: Database was not shut down normally,但 mysqld 卡在启动阶段,说明 InnoDB 自动恢复没走完。这不是文件损坏,是 recovery 流程被阻断了。
关键动作不是修表,而是放行恢复:
- 检查配置:确认
my.cnf里没设innodb_force_recovery = N(N > 0),这个值会禁用部分恢复逻辑,反而让启动卡住 - 清空异常锁文件:删掉
ib_logfile*和ibtmp1(仅当确定无未提交事务时;有 binlog 的话更稳妥) - 重启 mysqld,让它自己重放 redo log——多数情况下几秒内就能起来
- 真起不来?再试
innodb_force_recovery = 1,启动后立刻mysqldump导出数据,然后重建实例
注意:innodb_force_recovery 是导出手段,不是修复开关;设成 4 以上就禁止 INSERT/UPDATE/DELETE,别长期开着。
修复后验证和防复发要点
修完启动成功不等于万事大吉。系统表哪怕只有一行权限记录错乱,后续用户授权、创建数据库都可能静默失败。
必须做这几件事:
- 登录后立刻跑:
mysql_upgrade -u root -p—— 它会校验系统表结构,补缺失字段(比如 MySQL 5.7 升 8.0 后常见) - 检查权限是否生效:
SELECT User,Host FROM mysql.user;能查出来且没乱码,才算真正恢复 - 别跳过备份:
mysqldump --all-databases --single-transaction > full_backup.sql,下次出事不用重走一遍 - 预防比修复重要:把
innodb_flush_log_at_trx_commit = 1和sync_binlog = 1设上,断电时最多丢一个事务,不会崩表
最易被忽略的一点:修复完别急着加业务流量。先用慢查询日志或 pt-query-digest 抽样看前 10 分钟的 SQL 是否全量返回预期结果——有些表看似修好了,但某几行数据已静默损坏,只有业务读到才暴露。











