直接复制 mysql.user 表行会失败,因为该表仅存储认证信息而不存权限,实际权限分散在多张系统表中;正确做法是用 show grants + create user + grant 三步导出并重放权限语句,且需严格匹配主机名。

直接复制 mysql.user 表行会失败,为什么?
因为 mysql.user 表只存认证信息(如 plugin、authentication_string),不存权限;实际权限分散在 mysql.db、mysql.tables_priv、mysql.procs_priv 等多张表里。直接 INSERT INTO mysql.user 不仅无效,还可能破坏密码哈希或触发安全限制(比如 skip-grant-tables 关闭时写入被拒)。
用 SHOW GRANTS + CREATE USER + GRANT 三步走最可靠
这是官方推荐、兼容性最好、也最容易验证的方式。核心是把源用户的权限语句完整导出,再套用到新用户上:
- 先创建新用户:
CREATE USER 'newuser'@'%' IDENTIFIED BY 'password';(注意主机名要匹配源用户,比如'olduser'@'localhost'的对应项是'newuser'@'localhost') - 查源用户所有权限:
SHOW GRANTS FOR 'olduser'@'%';—— 输出结果是一条或多条GRANT ... ON ... TO ...语句 - 把输出里的
'olduser'@'%'全局替换成'newuser'@'%',然后逐条执行GRANT语句
注意:如果源用户有 WITH GRANT OPTION,记得保留;若目标 MySQL 版本 ≥ 8.0,且用了角色(ROLE),SHOW GRANTS 会包含 SET DEFAULT ROLE,也要一并复制。
自动化脚本里别漏掉 FLUSH PRIVILEGES?其实不用
从 MySQL 5.7.6 起,所有通过 GRANT、CREATE USER 等 DCL 语句做的变更,都会自动刷新权限缓存。FLUSH PRIVILEGES 只在直接修改系统表(如 INSERT INTO mysql.user)后才需要——而那种做法本身就不该用。所以只要全程走 GRANT 流程,执行完最后一条 GRANT 就立即生效,无需额外命令。
MySQL 8.0+ 用户可考虑 CREATE USER ... AS 语法
8.0.19+ 支持快捷克隆:CREATE USER 'newuser'@'%' IDENTIFIED BY 'pass' AS 'olduser'@'%';。它会复制认证插件、密码哈希、SSL 设置和资源限制,但不复制任何权限——权限仍需后续 GRANT 或 SHOW GRANTS 补全。这个语法省的是用户属性,不是权限逻辑,别误以为一步到位。
真正容易被忽略的点是主机名匹配:哪怕源用户是 'user'@'192.168.1.%',新用户也必须用完全相同的主机模式,否则 GRANT 语句执行会报错 ERROR 1133 (42000): Can't find any matching row in the user table。











