不能直接导出mysql.user表迁移权限,因其仅存全局账号和认证信息,权限分散在至少6张表中,且authentication_string哈希算法跨版本不兼容(5.7用mysql_native_password,8.0用caching_sha2_password),硬插会导致密码无效或权限缺失。

直接导出 mysql.user 表迁移权限,99% 会失败——不是少权限,就是登录不了,甚至服务启动报错。必须用逻辑导出 + 分表控制 + 版本适配三步走。
为什么不能 SELECT * FROM mysql.user 导出再 INSERT?
因为权限分散在至少 6 张表里,mysql.user 只存全局账号和认证信息;mysql.db、mysql.tables_priv、mysql.columns_priv、mysql.procs_priv、mysql.proxies_priv 各管一层。漏一张,用户就可能连得上但查不了库、删不了表。更关键的是:authentication_string 字段是哈希值,MySQL 5.7 默认用 mysql_native_password 算法,8.0 默认用 caching_sha2_password,跨版本硬插会导致密码无效。
正确导出权限表的 mysqldump 命令组合
必须显式指定表名、跳过锁、加事务一致性(InnoDB)、排除无关系统表:
mysqldump -u root -p --single-transaction --skip-lock-tables --databases mysql --tables user db tables_priv columns_priv procs_priv proxies_priv role_edges default_roles > mysql_grants.sql- MySQL 5.6 及以下不支持
--single-transaction对 MyISAM 表生效,若系统表含 MyISAM(如老版本mysql.plugin),需停写或接受短暂不一致 - 务必删掉导出文件开头的
CREATE DATABASE IF NOT EXISTS `mysql`;,否则导入时可能覆盖目标实例的系统库结构 - 跳过
mysql.plugin、mysql.servers、mysql.help_*等非权限表,避免因插件版本不兼容报错
导入前必须做的三件事
直接 mysql 必然失败——主键冲突、字段缺失、权限叠加全都会发生:
- 先清空目标库权限表:
TRUNCATE TABLE mysql.user;,再按顺序执行TRUNCATE TABLE mysql.db;、TRUNCATE TABLE mysql.tables_priv;等(顺序不能乱) - 确认目标 MySQL 版本 ≥ 源版本,否则 8.0 导出的
account_locked、password_last_changed字段在 5.7 会触发 ERROR 1054 - 导入后立刻执行:
FLUSH PRIVILEGES;——内存缓存不刷新,新用户永远“不存在”
跨大版本(如 5.7 → 8.0)必须绕开 dump 表,改用 SHOW GRANTS
8.0 的 mysql.user 表结构变更剧烈,且 GRANT 不再隐式创建用户。这时 mysqldump 导出的 INSERT 已不可信:
- 在源库逐个执行:
SHOW CREATE USER 'u'@'h';和SHOW GRANTS FOR 'u'@'h';,手动补全IDENTIFIED WITH mysql_native_password BY 'xxx'(如需兼容旧客户端) - 或用
pt-show-grants自动生成可执行语句:pt-show-grants --user=root --password=xxx > grants.sql,它自动处理角色、跳过匿名用户、适配字段差异 - 导入前,确保目标库已启用对应认证插件:
SELECT plugin FROM mysql.user WHERE user='root';,若为caching_sha2_password但客户端不支持,得提前运行ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'xxx';
真正容易被忽略的不是命令怎么写,而是“清空权限表”和“FLUSH PRIVILEGES”的执行时机——它们必须紧挨着导入操作,中间不能有其他 DML 或重启。否则权限状态永远卡在旧缓存里。


















