mysql 8.0+ 直接导出 mysql.user 表迁移权限不可行,因字段变更、密码哈希格式与认证插件不兼容;推荐用 show grants for 生成授权语句跨版本迁移,或使用 pt-show-grants 工具并过滤敏感内容。

直接导出 mysql.user 表数据迁移权限,在 MySQL 8.0+ 上基本不可行——字段缺失、密码哈希格式不兼容、认证插件不匹配,导入后几乎必然报错或用户无法登录。
为什么 mysqldump mysql.user 在 8.0+ 上会失败
MySQL 8.0 彻底重构了用户认证体系:mysql.user 表新增了 plugin、authentication_string 等字段,且弃用了 Password 字段;同时默认使用 caching_sha2_password 插件。而 dump 出的 INSERT 语句若直接执行,会因字段数量/类型不一致被拒绝,或即使插入成功,用户也无法通过密码认证。
常见错误包括:
ERROR 1364 (HY000): Field 'plugin' doesn't have a default valueERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded- 用户能创建但
mysql -u xxx -p登录时提示Access denied
导出 mysql.user 表仅适用于同版本且已停服的离线迁移
该方式要求源和目标 MySQL 版本完全一致(如都是 5.7.40 或都是 8.0.33),且必须停掉双方 MySQL 服务,直接拷贝整个 /var/lib/mysql/mysql/ 目录。即便如此,仍需额外操作:
- 目标服务器上先备份原有
mysql库目录(如重命名为mysql.bak) - 复制后执行
chown -R mysql:mysql /var/lib/mysql/mysql,否则启动失败 - 启动后必须立即执行
FLUSH PRIVILEGES;,否则部分权限不生效 - 若目标库已有同名用户,会触发主键冲突,需手动清理或用
REPLACE INTO替代INSERT INTO
替代方案:用 SHOW GRANTS FOR 生成可执行语句
这是跨版本、最安全、也最可控的权限迁移路径。它不依赖表结构,只依赖 SQL 接口,5.6–8.4 全支持。
实操步骤:
- 在源库执行:
SELECT CONCAT('SHOW GRANTS FOR ''', user, '''@''', host, ''' ;') FROM mysql.user WHERE user NOT IN ('mysql.infoschema','mysql.session','mysql.sys','root'); - 逐条运行输出的
SHOW GRANTS FOR 'u1'@'%' ;,复制每条返回的GRANT ... TO ...语句 - 在目标库中,先用
CREATE USER 'u1'@'%' IDENTIFIED BY 'xxx';创建空用户(注意:8.0+ 必须显式指定密码) - 再执行对应的
GRANT语句;若有WITH GRANT OPTION,确保该用户已存在后再授予权限 - 最后统一执行一次
FLUSH PRIVILEGES;
关键细节:如果源库用户使用了角色(ROLE),还需额外执行 SHOW GRANTS FOR ROLE 'rolename'; 并导出 mysql.role_edges 中的映射关系。
pt-show-grants 工具导出更省事但需过滤敏感内容
pt-show-grants 是 Percona Toolkit 提供的专用工具,能自动拼接完整授权语句并去重,比手写 SQL 更高效。但它默认会输出 CREATE USER 和含明文密码哈希的 IDENTIFIED BY PASSWORD 行——后者在 8.0+ 已废弃且会导致语法错误。
安全用法:
- 加
--no-create-user:跳过CREATE USER,自己控制用户创建逻辑(比如统一用mysql_native_password插件) - 加
--user=app_rw:限定只导某个应用账号,避免导出管理账号 - 用
sed '/IDENTIFIED BY PASSWORD/d'过滤掉所有带该关键词的行 - 导出后检查是否含
GRANT PROXY或SET DEFAULT ROLE等 8.0+ 新特性语句,目标库版本不支持时需手动删减
真正容易被忽略的是:所有导出的 GRANT 语句执行前,目标库必须已存在对应数据库(ON db1.* 要求 db1 已建好),否则会报 ERROR 1044 (42000)。











