mysql_upgrade不能修复已损坏的权限表,仅能升级可正常读取的系统表结构;若mysql.user等表物理损坏(如文件缺失或MYI错误),它会报错退出,因依赖MySQL正常加载元数据。

mysql_upgrade 不能修复已损坏的权限表,它只负责升级结构——前提是表还能被 MySQL 正常读取。如果连 mysql.user 都报 Table 'mysql.user' doesn't exist,说明物理层已崩溃,mysql_upgrade 会直接退出,甚至可能让后续启动失败。
为什么 mysql_upgrade 总是失败?
常见错误现象:mysql_upgrade 启动后立刻报错退出,日志里出现 Failed to open mysql.user 或 Incorrect information in file: './mysql/user.MYI'。这不是工具问题,而是它根本没机会干活——底层文件已不可读。
根本原因在于:mysql_upgrade 是“升级器”,不是“抢救器”。它依赖 MySQL 能正常加载系统库元数据。一旦 .frm、.MYI(MyISAM)或 .ibd(InnoDB)损坏或缺失,它连表结构都解析不了,自然无法补字段、加索引。
- MySQL 5.7 及以前默认用 MyISAM 存
mysql.user,损坏多表现为.MYI文件异常 - MySQL 8.0+ 改用 InnoDB + 数据字典,此时
mysql.user实际由data_dictionary管理,mysql_upgrade更难介入物理修复 - 误删
/var/lib/mysql/mysql/下任意一个文件(哪怕只是user.frm),都可能导致整个系统库不可识别
跳过权限验证后该修什么?
停掉 MySQL,加 --skip-grant-tables --skip-networking 启动,能连进去不代表问题解决——此时你面对的是一个“裸”实例:权限表存在但内容无效,或表结构残缺。
先确认损坏程度:
- 执行
USE mysql;后查SHOW TABLES;—— 如果user、db、tables_priv缺失,说明表定义文件(.frm或.sdi)已丢 - 执行
SELECT * FROM user LIMIT 1;报Incorrect key file,基本锁定.MYI损坏(MyISAM 场景) - 执行
SELECT VERSION(), @@skip_grant_tables;确认当前确实在跳过模式,避免误判
修法取决于引擎:
- MyISAM 表:用
myisamchk -r /var/lib/mysql/mysql/user.MYI强制修复(必须停服务);若提示key file is old,加-o参数重试 - InnoDB 表:不适用
REPAIR TABLE,也不该手动改.ibd;优先尝试重启 MySQL,让其自动触发崩溃恢复(innodb_force_recovery可配合启用) - 8.0+ 数据字典损坏:
--initialize-insecure是更稳妥的选择,它重建完整系统库结构,且不碰业务库
手动重建权限表时最容易踩的坑
很多人导出旧 mysql.user 再 INSERT 到新表,结果登录依旧失败——问题不在数据,而在结构不匹配。
- 字段顺序错:MySQL 5.7 的
password字段在 8.0 已废弃,换成authentication_string;漏掉password_history(8.0+)或plugin字段会导致认证失败 - 索引缺失:没重建
PRIMARY KEY或user@host联合索引,查询性能暴跌,甚至触发全表扫描式权限检查 - 忽略
FLUSH PRIVILEGES:在--skip-grant-tables模式下执行完UPDATE或INSERT后,必须显式执行该命令,否则内存缓存不会更新 - 复制文件搞混路径:把新实例生成的
mysql/user.ibd直接覆盖到旧目录,却忘了同步mysql/user.sdi(8.0+)或mysql/user.frm(5.7),导致元数据不一致
真正危险的操作,不是修得慢,而是修得“看起来成功了”——表能 SELECT,用户能 CREATE,但某天突然发现 root@localhost 无法访问 information_schema,或者新建用户始终走 auth_socket 认证。这类隐性损坏,往往要等业务出问题才暴露。


















