MySQL无“数据库对象所有权”概念,所谓转移实为迁移权限;直接mysqldump mysql库会导致认证失败、权限叠加等问题;正确做法是用pt-show-grants或手工生成CREATE USER+GRANT语句分步导入,并校验插件、表数及连接。

MySQL 里没有“数据库对象所有权”这个概念——它不像 PostgreSQL 或 SQL Server 那样支持 OWNER 属性或 ALTER TABLE ... OWNER TO 语法。所谓“转移所有权”,实际是转移访问控制权,即:让另一个用户能以预期权限操作表、视图、存储过程等对象。
你真正要做的,是迁移权限定义,而不是“所有权”。搞错这点,直接复制 mysql.user 表或用 mysqldump mysql 全量导入,极大概率导致权限叠加、认证失败、甚至服务启动异常。
为什么不能直接 mysqldump mysql 库再导入?
-
mysql系统库包含大量运行时状态字段(如password_last_changed、account_locked),跨版本导入会触发校验失败或忽略; -
authentication_string字段在 5.7 和 8.0+ 使用不同哈希算法(mysql_native_passwordvscaching_sha2_password),硬导出会丢失登录能力; - 直接插入
user表不触发权限缓存刷新,必须FLUSH PRIVILEGES,但该命令在某些配置下被禁用(如启用了skip-grant-tables); - 多次导入同名用户会导致
GRANT语句叠加,比如一个用户本应只有SELECT,结果因重复导入获得INSERT权限,造成越权。
正确做法:用 pt-show-grants 或手工生成 GRANT 语句
最安全、可审计、跨版本兼容的方式,是只导出「人能读、人能改、人能验证」的授权语句:
-
安装 Percona Toolkit 后执行:
pt-show-grants -u root -p --no-version-check > grants.sql
它自动处理 5.7/8.0 密码插件差异,并跳过系统内置账户(如mysql.session); -
若无法安装第三方工具,用以下查询手动生成(适配 5.7+):
MySQL8 CRM Schema Design Expert下载面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
SELECT CONCAT('CREATE USER \'', user, '\'@\'', host, '\' IDENTIFIED WITH \'', plugin, '\' AS \'', authentication_string, '\';') FROM mysql.user WHERE user NOT IN ('root', 'mysql.session', 'mysql.sys');SELECT CONCAT('GRANT ', GROUP_CONCAT(privilege), ' ON ', IF(db='', '*.*', CONCAT('`', db, '`.*')), ' TO \'', user, '\'@\'', host, '\';') FROM (SELECT user, host, db, privilege FROM (SELECT user, host, db, 'SELECT' AS privilege FROM mysql.db WHERE Select_priv = 'Y' UNION ALL SELECT user, host, db, 'INSERT' FROM mysql.db WHERE Insert_priv = 'Y') t) tt GROUP BY user, host, db;
导入时务必分两步:
- 先执行所有
CREATE USER语句(避免GRANT报错 “user does not exist”); - 再执行所有
GRANT语句; - 最后手动验证:
SHOW GRANTS FOR 'app_user'@'10.20.%';
迁移后必须检查的三个细节
-
SELECT user, host, plugin, account_locked FROM mysql.user WHERE user = 'xxx';—— 确认认证插件和锁状态是否与源库一致; -
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'your_db';对比源/目标表数量,防止部分GRANT因数据库不存在而静默失败; - 应用连接测试必须用真实账号(非
root),且连接串中明确指定?plugin=caching_sha2_password(若目标为 8.0+);
跨大版本迁移(如 5.7 → 8.0)时,mysql_upgrade 已废弃,必须靠 mysqld --upgrade=FORCE 初始化系统表结构——这步漏掉,GRANT 可能写入失败却无报错。
真正的难点不在导出,而在“权限语义对齐”:同一个 GRANT SELECT ON db.* 在不同 MySQL 版本中隐含的列级权限行为可能不同。别跳过人工核对。










