mysqldump 不能导出权限,仅导出结构和数据;权限存于 mysql 系统库的 user、db 等表,默认被排除;正确方式是用 show grants 结合查询 mysql.db 等表并过滤目标库权限。

mysqldump 不能导出权限,它只导结构和数据
很多人误以为 mysqldump 加上 --all-databases 或指定库就能把用户权限一起导出来,其实不会。mysqldump 默认只访问 INFORMATION_SCHEMA 和业务库,而权限信息存在 mysql 系统库的 user、db、tables_priv 等表里——这些表默认被 mysqldump 排除(尤其当使用 --skip-lock-tables 或低权限账号时更明显)。
所以哪怕你用 mysqldump --databases myapp,也完全不包含任何 GRANT 语句。
真正导出单个库权限的正确方式:用 mysql 命令查 + 拼 GRANT
MySQL 没有内置“导出某库所有权限”的一键命令,但可以通过查询 mysql.db 和 mysql.tables_priv 表,结合 SHOW GRANTS 手动构造。关键是要先拿到所有对目标库有权限的账号:
- 运行
SELECT User,Host FROM mysql.db WHERE Db='myapp';获取账号列表 - 对每个
User@Host执行SHOW GRANTS FOR 'user'@'host';,再用grep过滤出含ON myapp\.的行 - 注意:
SHOW GRANTS返回的是完整权限语句,可能包含全局或其它库权限,必须过滤,否则就“越界”了
一个实用的 shell 一行命令(需有 SELECT 权限且能连 mysql 系统库):
mysql -Nse "SELECT CONCAT('SHOW GRANTS FOR ''',User,'''@''',Host,''';') FROM mysql.db WHERE Db='myapp'" | mysql -N | grep 'ON `myapp`'
为什么不能直接 mysqldump mysql.db 并恢复?
直接导出 mysql.db 表看似简单,但实际风险很高:
-
mysql.db表结构在不同 MySQL 版本中字段数可能变化(比如 5.7 有Grant_priv,8.0+ 改为角色模型),跨版本恢复大概率失败 - 该表不包含密码哈希、plugin、account locking 等字段,单独导入会导致用户状态不一致
- 恢复时若未停服或未禁用
sql_log_bin,还会写入 binlog,引发主从权限不一致 -
mysqldump mysql db导出的是 INSERT 语句,不是 GRANT,执行后权限行为不可预测(例如旧权限残留、大小写敏感问题)
安全导出 + 可重放的权限脚本建议
最稳妥的做法是生成纯 GRANT/REVOKE 语句,而不是 dump 表。推荐组合使用:
- 用
SELECT查mysql.db+mysql.tables_priv+mysql.procs_priv,拼出最小粒度的权限语句 - 对每个匹配账号,优先用
SHOW GRANTS FOR ...,再用sed和awk提取目标库相关行,例如:mysql -Nse "SELECT User,Host FROM mysql.db WHERE Db='myapp'" | while read u h; do mysql -Nse "SHOW GRANTS FOR '$u'@'$h'" | grep 'ON `myapp`'; done - 务必在目标环境执行前检查语句是否含
WITH GRANT OPTION—— 它会赋予被授权者再授权能力,容易被忽略但影响很大
真正麻烦的不是导出,而是确保“只导这个库、只涉及这些账号、不带意外权限”。漏掉 tables_priv 里的列级权限,或没处理 DEFINER 相关存储过程权限,都可能导致迁移后功能异常。











