应使用 show grants for 'user'@'host' 导出权限,而非直接查 mysql.user 表;需逐用户执行、处理角色链、过滤空权限语句、适配密码插件与ssl要求。

直接查 mysql.user 表导出的权限不完整
很多人用 SELECT * FROM mysql.user 导出用户信息,但这样只能看到全局权限字段(如 Select_priv、Grant_priv),而数据库级、表级、列级、存储过程等细粒度权限全在其他系统表里。MySQL 8.0+ 的权限模型更分散,mysql.role_edges、mysql.procs_priv、mysql.tables_priv 都得查。只读 mysql.user 会漏掉 90% 以上真实权限。
用 SHOW GRANTS FOR 'user'@'host' 是最可靠方式
这是 MySQL 官方推荐的权限导出逻辑,它会自动聚合所有层级权限并生成可执行的 SQL 语句。关键点在于:必须对每个用户逐条执行,不能靠单条 SQL 批量拼接——因为 SHOW GRANTS 不支持 IN 或子查询。
- 先获取所有非系统用户(排除
'mysql.infoschema'、'mysql.session'等内置账户):SELECT CONCAT('''', user, '''@''', host, '''') FROM mysql.user WHERE user NOT IN ('mysql.infoschema', 'mysql.session', 'mysql.sys', 'root') AND account_locked = 'N'; - 把结果复制进脚本循环调用:
SELECT CONCAT('SHOW GRANTS FOR ', CONCAT('''', user, '''@''', host, ''''), ';') AS stmt FROM mysql.user WHERE user NOT IN ('mysql.infoschema', 'mysql.session', 'mysql.sys') AND account_locked = 'N'; - 执行输出的每条
SHOW GRANTS,再重定向到文件(Linux 下建议用mysql -u root -p -e "..." > grants.sql)
MySQL 8.0+ 要额外处理角色(role)和默认角色
如果启用了角色机制,SHOW GRANTS FOR 默认不显示角色所含权限,除非加 WITH ADMIN OPTION 或显式指定 USING role_name。更稳妥的做法是:先查用户默认角色:
SELECT default_role FROM mysql.user WHERE user = 'xxx';,再对每个角色单独执行
SHOW GRANTS FOR 'role_name'@'%'。否则导出的脚本还原后,用户可能没有实际权限。注意:CREATE ROLE 和 SET DEFAULT ROLE 语句也得一并导出,否则权限链断裂。
导出后别直接 source,先检查三类问题
生成的 grants.sql 文件里常见陷阱:
-
GRANT USAGE ON *.* TO ...这类空权限语句可以删掉,它没实际作用,还可能干扰后续GRANT - 包含
IDENTIFIED WITH caching_sha2_password BY ...的语句,在目标库密码插件不同时会失败,建议手动替换成IDENTIFIED BY或提前确认插件兼容性 - 若源库有
REQUIRE SSL或 IP 白名单(REQUIRE SUBJECT),目标环境不满足时会报错Access denied for user,需提前核对
权限导出不是“一键复制”,重点在补全角色链、过滤无效语句、适配目标环境的认证方式——漏掉任意一项,还原后的用户都可能无法登录或无权操作。











