安全导出MySQL用户授权语句的可靠方式是查询mysql系统库并手动拼接GRANT语句,需适配版本差异(≥5.7.6)、保留plugin字段、处理空Db为*.*,或使用pt-show-grants工具自动处理。

导出所有用户的授权语句用 SHOW GRANTS 配合 mysqldump 不行
直接执行 mysqldump --all-databases 不会导出用户权限,它只备份库表结构和数据。SHOW GRANTS 本身不支持批量对所有用户一次性输出,必须逐个指定用户名和主机。硬写循环脚本前得先确认:MySQL 版本是否 ≥ 5.7.6?因为 mysql.db、mysql.tables_priv 等系统表的字段和权限逻辑在 8.0 有重大变更(比如角色、密码历史、authentication_string 替代 password),混用会导致迁移后权限失效或登录失败。
安全导出完整授权语句的可靠方式是查询 mysql 系统库 + 手动拼接
核心思路:从 mysql.user、mysql.db、mysql.tables_priv、mysql.procs_priv、mysql.proxies_priv 中提取有效账户(排除 'root'@'localhost' 这类内置管理账号可选),再用 CONCAT 拼成标准 GRANT 语句。注意以下几点:
-
user表里的plugin字段必须保留,8.0 默认是caching_sha2_password,迁移到老版本要改成mysql_native_password -
db表中Db为空字符串表示全局权限,不能漏掉ON *.*的判断 - 用
SELECT ... INTO OUTFILE导出时需确保 MySQL 有写入目标路径权限,且secure_file_priv未禁用该功能 - 推荐用如下 SQL 生成基础
GRANT(不含角色、密码):SELECT CONCAT('GRANT ', GROUP_CONCAT(priv SEPARATOR ', '), ' ON ', IF(db='', '*.*', CONCAT('`', db, '`.*')), ' TO \'', user, '\'@\'', host, '\';') AS stmt FROM ( SELECT user, host, db, CASE WHEN Select_priv='Y' THEN 'SELECT' END AS priv FROM mysql.db UNION ALL SELECT user, host, '', 'SUPER' FROM mysql.user WHERE Super_priv='Y' -- 其他权限字段依此类推,需覆盖 Insert_priv/Update_priv/Delete_priv 等 ) t GROUP BY user, host, db;
用 pt-show-grants 工具比手写 SQL 更稳但依赖 Percona Toolkit
如果服务器已装 Percona Toolkit(推荐 3.5+),pt-show-grants 是最省心的选择——它自动处理版本差异、过滤掉无意义账户、补全 IDENTIFIED WITH 和密码哈希格式。运行前确认:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 目标 MySQL 实例允许本地 socket 或 TCP 连接(
--host参数指定) - 连接用户必须有
SELECT权限访问mysql库所有相关表 - 加
--skip-roles可避免 8.0 角色语句干扰纯用户迁移 - 典型命令:
pt-show-grants --host=localhost --user=root --password=xxx > grants.sql
导入时最常踩的坑是权限语句顺序和 FLUSH PRIVILEGES 时机
生成的 grants.sql 文件不能直接用 mysql 执行,原因有三:
- 多个
GRANT对同一用户重复执行会报错(如ERROR 1396 (HY000)),需先用DROP USER IF EXISTS 'u'@'h';清理 -
CREATE USER必须在GRANT前,否则报ERROR 1133 (42000);而pt-show-grants默认不输出CREATE USER,得自己补 -
FLUSH PRIVILEGES在导入末尾执行一次即可,中间每条GRANT后不用刷,否则拖慢速度 - 若目标库启用了
sql_mode=STRICT_TRANS_TABLES,某些旧版导出的空IDENTIFIED BY语句会失败,需替换为IDENTIFIED WITH caching_sha2_password AS '$A...'
真正麻烦的是跨大版本迁移(如 5.7 → 8.0):密码字段名、默认认证插件、权限粒度都变了,光靠导出语句不够,还得同步检查 mysql.user 表结构差异和客户端连接参数。










