MySQL 8.0权限丢失不可直接还原旧版--all-databases备份,因表结构不兼容;应先执行FLUSH PRIVILEGES排除缓存问题,再查mysql.user和mysql.db确认权限字段值,有SHOW GRANTS备份时优先重放SQL恢复。

不能直接还原旧版 mysqldump --all-databases 备份,8.0 的 mysql.user 表结构已不兼容;若无提前导出的 SHOW GRANTS 语句或 ROW 格式 binlog,权限元数据大概率不可逆丢失。
确认是不是真丢了权限,还是只是缓存/连接复用假象
很多“权限丢失”其实只是内存缓存没刷新。先别急着进安全模式,执行:FLUSH PRIVILEGES; 看是否恢复。如果仍报 Access denied 或某用户能登录但 SHOW DATABASES 报错 1142,再查表:
-
SELECT User, Host, Select_priv, authentication_string, plugin FROM mysql.user WHERE User = 'your_user';—— 检查权限字段是否为NULL或0(8.0+ 是TINYINT(1),不是'Y') -
SELECT * FROM mysql.db WHERE User = 'your_user';—— 确认库级权限是否为空 - 注意:8.0 已移除
Password字段,authentication_string必须非空,且password_last_changed不能为空时间戳,否则即使密码对也会拒绝登录
有 SHOW GRANTS 备份时最快恢复方式
这是最安全、最推荐的路径——它绕过所有表结构差异,只重放逻辑授权语句。前提是升级前或误删前你执行过类似操作并保存了输出:
- 在旧实例或备份中导出:
mysql -u root -p -e "SELECT CONCAT('SHOW GRANTS FOR ''',User,'''@''',Host,''';') FROM mysql.user WHERE User NOT IN ('mysql.infoschema','mysql.session','mysql.sys')" | mysql -u root -p --skip-column-names | sed 's/$/;/g' > user_grants.sql - 在新实例中执行:
mysql -u root -p -
必须立刻跟一句:
FLUSH PRIVILEGES;—— 否则权限不会加载到运行时内存 - 验证:
SHOW GRANTS FOR 'app_user'@'%';看是否与预期一致
没有 SHOW GRANTS 但有 ROW 格式 binlog
这是唯一可能“反向提取原始用户行”的机会,但要求严格:
- 先确认:
SHOW VARIABLES LIKE 'log_bin';返回ON,且binlog_format = 'ROW' - 定位误删前后日志:
SHOW MASTER LOGS;结合系统时间筛选疑似文件(如mysql-bin.000012) - 解析并搜索最后一次插入该用户的完整行:
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000012 | grep -A 50 "INSERT INTO `mysql`.`user`" | grep -B 20 "your_user" - 关键字段一个都不能少:
authentication_string、password_last_changed(必须是非 NULL 时间戳)、account_locked、所有_priv字段值(如Select_priv = 1) - 在
--skip-grant-tables模式下手动INSERT或UPDATE,之后务必FLUSH PRIVILEGES;
连 binlog 都没有时只能重建系统库
这不是“修复”,而是彻底重置权限体系。适用于 mysql.user 表物理损坏(如报 Table 'mysql.user' doesn't exist)或字段全被清空且无任何外部参考的情况:
- 停服务:
systemctl stop mysqld,再killall mysqld确保无残留进程 - 备份整个
/var/lib/mysql(含ibdata1和日志文件),然后仅移走mysql/子目录:mv /var/lib/mysql/mysql /var/lib/mysql/mysql.bak - 用同版本
mysqld初始化:mysqld --initialize-insecure --datadir=/var/lib/mysql --user=mysql - 启动:
systemctl start mysqld,此时root@localhost密码为空,立即登录执行:ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpass'; - 重建后必须补全用户:不能直接还原旧
mysqldump,而应从mysql.bak/user.frm或其他环境里人工比对字段,逐个CREATE USER+GRANT;特别注意mysql.infoschema@localhost必须存在且Host = 'localhost'
最容易被忽略的是 password_last_changed 和 Account_locked 这两个字段:8.0 默认强制校验,哪怕你把 authentication_string 写对了,这两个字段为空或非法值,照样登录失败。不要假设“密码对了就行”。











