先执行select 1 from mysql.user limit 1;报错“table 'mysql.user' doesn't exist”或“incorrect information in file”才算确诊损坏;若仅access denied但能查到user表行,则属plugin、authentication_string异常或flush privileges未生效,非物理损坏。

权限表损坏但 MySQL 能启动,怎么确认是真坏了
别一看到 Access denied 就动手修。先连上去执行:SELECT 1 FROM mysql.user LIMIT 1;。报错 Table 'mysql.user' doesn't exist 或 Incorrect information in file: './mysql/user.frm' 才算确诊。如果只是登录失败但能查到 mysql.user 行,大概率是 plugin 字段为空、密码哈希格式不匹配,或 FLUSH PRIVILEGES 没生效——这不算物理损坏,不该走重建流程。
用 mysqld --skip-grant-tables 启动后必须加 --skip-networking
只加 --skip-grant-tables 是危险操作:MySQL 会跳过权限检查,但依然监听网络端口,任何远程连接都能无密执行任意 SQL。必须配套加 --skip-networking,让 mysqld 只接受本地 socket 连接。
配置文件方式(如 /etc/my.cnf)要写在 [mysqld] 段下,改完必须彻底杀进程:killall mysqld,不能只 systemctl restart mysqld——旧进程残留会导致后续所有修复动作无效。
验证是否生效:mysql -u anyuser -e "SELECT USER();" 应返回 anyuser@localhost,而不是 Access denied。
mysql_upgrade --force 失败时,该用 --initialize-insecure 重刷系统表
mysql_upgrade 本质是补字段、建索引、同步数据字典。但它依赖现有 mysql 库结构基本完整。一旦 user.ibd 和 user.frm(或 user.sdi)缺一,或主键/UNIQUE 约束损坏,它就会卡住或报错。
此时应停服务,备份整个 /var/lib/mysql/mysql/ 目录(不是只拷几个文件),然后执行:
mysqld --initialize-insecure --datadir=/var/lib/mysql --user=mysql
注意三点:
- 该命令会重写
mysql系统库所有表结构与默认行(包括 root@localhost),但不会动业务库 - 必须指定
--datadir,否则可能初始化到错误路径 - 8.0+ 版本中,
--initialize-insecure生成的 root 密码为空,登录后需立刻用ALTER USER设置强密码
修复后别忘了验证 plugin 和密码哈希格式
重刷后的 mysql.user 表里,plugin 字段默认是 caching_sha2_password(8.0+)或 mysql_native_password(5.7)。如果应用连接用的是老客户端或未配插件,会报 Client does not support authentication protocol。
检查并修正:
SELECT User, Host, plugin, authentication_string FROM mysql.user WHERE User = 'root';
若需兼容旧协议,执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
最后务必运行 FLUSH PRIVILEGES;——这不是可选项,是强制加载磁盘数据到内存权限缓存的唯一方式。漏掉这步,你刚改的权限不会生效。











