MySQL 8.0 不支持 CREATE USER ... LIKE 语法,该语法属 MariaDB;正确做法是四步:CREATE USER + SHOW GRANTS + 替换用户名/Host 后执行 GRANT + FLUSH PRIVILEGES,并单独处理角色权限与目标库表存在性。

MySQL 8.0 没有 CREATE USER ... LIKE 语法,别试了
执行 CREATE USER 'newuser'@'%' LIKE 'olduser'@'%' 会直接报错 ERROR 1064 (42000)。这不是你配置漏了或版本没升对,是 MySQL 官方压根没实现这个语法——它属于 MariaDB 的功能,常被误传进 MySQL 场景。硬写只会中断脚本、浪费排查时间。
正确路径:SHOW GRANTS + CREATE USER + GRANT + FLUSH PRIVILEGES
这是唯一可靠、跨版本兼容的做法,核心在于分四步走,缺一不可:
- 先用
CREATE USER 'newuser'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd'显式建用户(注意指定认证插件,避免caching_sha2_password导致旧客户端连不上) - 执行
SHOW GRANTS FOR 'olduser'@'%',拿到原始授权语句 - 人工或脚本替换每条语句里的用户名和 host(如把
'olduser'@'%'替成'newuser'@'%'),过滤掉开头的GRANT USAGE ON *.* TO ...行(它不授实际权限,且依赖用户已存在) - 执行所有清洗后的
GRANT语句,最后补上FLUSH PRIVILEGES——即使 MySQL 8.0 大部分情况自动重载,显式刷一次最稳妥,尤其当权限表被直连修改过时
角色权限必须单独处理,SHOW GRANTS 不会返回
如果原用户被授予了角色(比如 app_reader),SHOW GRANTS FOR 'olduser'@'%' 输出里不会出现 GRANT app_reader TO ...。你得额外查 mysql.role_edges:
- 查关系:
SELECT FROM_USER, TO_USER FROM mysql.role_edges WHERE FROM_USER = 'olduser' - 对每个匹配项,执行
GRANT 'role_name' TO 'newuser'@'%' - 若需设默认角色,再加一句
SET DEFAULT ROLE 'role_name' TO 'newuser'@'%'
漏掉这步,新用户看起来“权限全”,实则无法访问角色所含的任何对象。
目标库/表不存在?GRANT 会直接失败
GRANT SELECT ON mydb.* TO ... 这类语句要求 mydb 必须已存在,否则报 ERROR 1044 (42000): Access denied for user ... to database 'mydb'。表级权限(如 ON mydb.mytable)更进一步,要求表结构也得存在。
- 迁移前先在目标实例跑
SHOW DATABASES和SHOW TABLES FROM db_name核验 - 缺失库就补
CREATE DATABASE IF NOT EXISTS mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci(字符集要和源一致) - 缺失表不能靠 GRANT 补,得提前同步 schema 或数据
最容易被忽略的是 host 匹配细节:'user'@'192.168.1.%' 和 'user'@'%.example.com' 是两套独立规则,DNS 解析行为、skip_name_resolve 配置都会影响最终匹配结果——别只盯着用户名改,host 得一并核对。


















