直接dump mysql库再导入会失败,是因为mysql系统库包含依赖运行时状态的表(如user、db),其数据与实例ID、socket路径、权限上下文强绑定,且部分表(如plugin、procs_priv)含二进制字段或触发器逻辑,跨实例导入将导致权限混乱、认证失败或服务启动异常。

MySQL多实例环境下用户权限无法自动同步,因为每个实例的mysql库完全独立,且系统表(如mysql.user、mysql.db)不参与任何复制机制——这不是配置漏了,而是设计如此。
为什么直接 dump mysql 库再导入会失败
直接mysqldump mysql导出后在其他实例执行mysql -u root mysql ,大概率导致登录失败、<code>Access denied或mysqld启动异常。原因很实在:
-
mysql库包含plugin、help_topic、time_zone等强耦合表,覆盖会破坏当前插件状态和时区数据 - 密码字段(
authentication_stringvs 已废弃的Password)和字段默认值(如password_last_changed)在5.7→8.0迁移中极易不兼容 - 跨版本导入可能触发
ERROR 1067 (42000): Invalid default value for 'password_last_changed'
用 SHOW GRANTS 导出 + 手动执行是最稳妥路径
SHOW GRANTS FOR 'user'@'host'生成的是纯逻辑授权语句,可读、可审、可移植,且绕开了所有底层表结构差异。但要注意几个实操细节:
- 必须对每个用户单独执行:
SHOW GRANTS FOR 'app'@'192.168.10.%';,不能只靠SELECT * FROM mysql.user粗筛 - 若含角色(MySQL 8.0+),需额外查
SELECT * FROM mysql.role_edges WHERE FROM_HOST = '192.168.10.%' AND FROM_USER = 'app';,否则角色继承链断裂 - 导出结果中若含
DEFINER(如存储过程),需确认目标实例是否存在该用户,否则CREATE PROCEDURE会报错 - 执行前建议在目标实例先
SET sql_log_bin = 0;,避免这些语句又被写入 binlog 引发循环或冲突
pt-show-grants 工具能批量但容易漏关键项
pt-show-grants是Percona Toolkit里最接近“自动化”的方案,但它默认行为有明显盲区:
- 不输出
CREATE USER语句,需加--no-create-user防止重复建用户报错;若真要重建,得配合--skip-privileges再手动补CREATE USER - 列级权限(如
GRANT SELECT(col1) ON db.t1)默认不显示,必须显式加--columns参数 - 带
WITH GRANT OPTION或PROXY用户的授权会被静默忽略,需人工核对 - 运行前务必确认源实例已启用
performance_schema,否则动态权限(如BACKUP_ADMIN)查不到
大规模部署必须用脚本或Ansible做幂等控制
人工逐台执行GRANT在5个以上实例时必然出错。脚本或Ansible不是为了“省事”,而是为规避三类硬伤:
- 同一账号的
Host值不一致(如有的写'%',有的写'192.168.10.%'),导致连接被拒绝但错误模糊 -
CREATE USER漏执行时,GRANT在8.0+会静默失败(不报错也不生效) - 角色未绑定
DEFAULT ROLE,新用户登录后权限不加载
验证环节不能省:SHOW GRANTS FOR 'u'@'h'结果比对、mysql.role_edges行数校验、以及用测试账号真实连接一次——光看SQL执行成功不等于权限真生效。


















