直接结论:mysql.user表“数据丢失”通常非行级删除而是结构损坏或字段异常;真丢数据时mysql_upgrade不能恢复,须跳过权限启动+手动重建或重置系统库。判断方法:先执行SELECT USER(), CURRENT_USER()和SHOW DATABASES,若无mysql库则属严重损坏;若报Table 'mysql.user' doesn't exist为物理损坏;若能查但plugin或authentication_string异常则为数据异常。

直接结论:mysql.user 表“数据丢失”通常不是行级删除,而是表结构损坏或权限字段异常;真丢数据(比如误删 root 用户)时,mysql_upgrade 不能恢复,必须用跳过权限启动 + 手动重建或重置系统库。
怎么判断是“数据丢失”还是“表损坏”
先连上 MySQL(哪怕报错也要试),执行:SELECT USER(), CURRENT_USER();。如果返回空或报 Access denied,再查系统库:
- 执行
SHOW DATABASES;—— 若看不到mysql库,说明mysql数据库目录缺失或不可读,属于严重损坏 - 执行
SELECT COUNT(*) FROM mysql.user;—— 若报Table 'mysql.user' doesn't exist或Incorrect information in file: './mysql/user.frm',是物理文件损坏 - 若能查出记录但
plugin字段为空、为auth_socket或密码哈希字段(authentication_string)为空/非法,则是权限数据异常,不是“表损坏”,不用重建,只需UPDATE
跳过权限验证后,为什么不能直接 INSERT 恢复用户
因为 5.7+ 默认 innodb_file_per_table=ON,mysql.user 是 InnoDB 表,且依赖数据字典一致性;强行 INSERT 可能导致启动失败或后续 FLUSH PRIVILEGES 报错。更关键的是:
-
mysql.user的主键、索引、默认值、生成列(如 8.0+ 的password_last_changed)必须严格匹配版本要求 - 手动写
INSERT容易漏掉account_locked、password_lifetime等字段,导致用户无法登录或被锁 - 8.0+ 中部分权限字段已迁入数据字典,
mysql.user表只是视图,直接写入无效
真正有效的恢复路径只有两条
确认损坏后,停服务、备份整个 /var/lib/mysql/mysql/ 目录(别只拷 .ibd),然后选下面一种:
- 适用 5.7 及以前、MyISAM 或轻度 InnoDB 损坏:
启动时加--skip-grant-tables --skip-networking,进库后执行mysql_upgrade -u root --force;它会检测并重建缺失的系统表(包括user、db),但前提是表结构元数据还能读取 - 适用所有版本、尤其 8.0+ 或彻底崩溃:
用mysqld --initialize-insecure --datadir=/var/lib/mysql重建全新mysql系统库(注意路径要对),再把原业务库(/var/lib/mysql/your_db/)下的.ibd和.frm(或.sdi)文件拷回;--initialize-insecure会生成空密码的root@localhost,之后立刻ALTER USER改密
容易被忽略的关键细节
很多人修完发现还是登不进去,问题往往出在:
-
--skip-networking必须加,否则远程攻击面大开,且某些版本会因网络初始化失败而卡住 - 改完配置后,必须
killall mysqld彻底杀进程,systemctl restart mysqld可能残留旧实例,导致新参数不生效 - 8.0+ 启动后第一次连接必须用
mysql -u root --socket=/var/run/mysqld/mysqld.sock(避免走 TCP 走插件认证),否则仍可能报plugin 'caching_sha2_password' could not be loaded - 重建后务必检查
plugin字段是否为caching_sha2_password(8.0+ 默认)或mysql_native_password(兼容老客户端),不匹配会导致连接拒绝


















