最直接风险是无法登录、权限失效或用户失权;必须用--skip-grant-tables启动进入安全模式修复,重置authentication_string、plugin等字段并执行flush privileges,最后清理参数正常重启。

MySQL 权限表(mysql.user、mysql.db、mysql.tables_priv 等)被误改后,最直接的风险是无法登录、权限失效或部分用户完全失权。不能直接用 mysqldump 备份恢复——因为备份可能早于误操作,且系统表不支持常规 DML 恢复逻辑。必须进入“安全模式 + 系统表修复”路径。
用 --skip-grant-tables 启动 MySQL 跳过权限校验
这是所有修复的前提:绕过已损坏的权限表加载流程,获得 root 级别无鉴权访问。
- 先停掉 MySQL:
sudo systemctl stop mysql(或mysqld进程) - 手动启动并跳过权限检查:
sudo mysqld --skip-grant-tables --skip-networking &
(--skip-networking防止未授权远程连接) - 此时可直接
mysql -u root连入,无需密码;但注意:所有权限检查被禁用,SELECT、UPDATE均可执行 - 若启动失败,常见原因是端口占用或
datadir路径不对,需加--datadir=/var/lib/mysql显式指定
手动修复 mysql.user 表的关键字段
误改后最常出问题的是 authentication_string(8.0+)、plugin、account_locked 和 password_expired 字段。空值、错误插件(如写成 mysql_native_password 但实际是 caching_sha2_password)、或 account_locked='Y' 会导致 root 登录失败。
- 确认当前 root 用户状态:
SELECT User, Host, plugin, authentication_string, account_locked FROM mysql.user WHERE User = 'root';
- 若
authentication_string为空或乱码,重置密码(以 8.0+ 为例):UPDATE mysql.user SET authentication_string = PASSWORD('newpass'), plugin = 'caching_sha2_password' WHERE User = 'root' AND Host = 'localhost'; - 务必同步更新
account_locked = 'N'和password_expired = 'N',否则即使密码正确也会被拒绝 - 修改后必须执行:
FLUSH PRIVILEGES;
(否则内存缓存不刷新,仍按旧规则校验)
从干净实例导出权限表结构与初始数据
如果本地没有可用备份,又不确定哪些行该保留,最稳妥的方式是重建权限表骨架:用同版本 MySQL 初始化一个新实例,导出其原始 mysql 库结构和基础账户数据。
- 在测试机上初始化干净实例:
mysqld --initialize-insecure --datadir=/tmp/mysql-clean
- 启动该实例并导出:
mysqldump --skip-lock-tables --databases mysql --tables user db tables_priv columns_priv --where="User IN ('root', '')" > clean-privs.sql - 回到故障实例(仍在
--skip-grant-tables模式下),清空并导入:TRUNCATE TABLE mysql.user; TRUNCATE TABLE mysql.db; SOURCE /path/to/clean-privs.sql;
- 注意:不要全量
mysqldump mysql,避免覆盖innodb_index_stats等运行时统计表
重启服务前必须验证并清理启动参数
忘记关掉 --skip-grant-tables 就重启,会导致整个库无权限控制——这是线上事故高发点。
- 退出 MySQL 客户端,杀掉带
--skip-grant-tables的mysqld进程(ps aux | grep skip-grant) - 检查配置文件(
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf)是否残留相关参数 - 正常启动:
sudo systemctl start mysql,再立刻验证:mysql -u root -p和SHOW GRANTS FOR 'root'@'localhost'; - 若仍报错
Access denied for user 'root'@'localhost',大概率是plugin字段和客户端默认认证方式不匹配,需在连接时显式指定:mysql -u root -p --default-auth=mysql_native_password
权限表修复不是“还原 SQL”那么简单——它依赖版本一致性、插件兼容性、以及对 FLUSH PRIVILEGES 时机的准确把握。最容易被忽略的是:修改完 mysql.user 后没刷权限,或者重启时忘了去掉跳过参数。这两步出错,前面所有操作都白做。










