MySQL 8.0 中 GRANT 不再自动创建用户,必须先用 CREATE USER(支持 IF NOT EXISTS 兼容 5.7),再用 GRANT 赋权;且默认认证插件为 caching_sha2_password,可能与旧客户端不兼容。

GRANT 在 MySQL 8.0 中不再自动创建用户
MySQL 8.0 彻底移除了 GRANT 隐式建用户的逻辑,哪怕 sql_mode 里没开 NO_AUTO_CREATE_USER 也没用。5.7 下 GRANT SELECT ON db.* TO 'u'@'%' IDENTIFIED BY 'p' 能直接建用户+赋权;8.0 执行这句会报 ERROR 1064 (42000),卡在 IDENTIFIED BY 位置。
根本原因是:8.0 要求用户存在性与权限分离,CREATE USER 和 GRANT 必须拆成两步。这不是配置开关能绕过的,是语法层硬性限制。
- 5.7 兼容写法(仍可用):
GRANT ... TO 'u'@'%' IDENTIFIED BY 'p' - 8.0 唯一合法写法:
CREATE USER 'u'@'%' IDENTIFIED BY 'p';+GRANT ... ON ... TO 'u'@'%'; - 若脚本要同时跑在 5.7 和 8.0 上,必须用
CREATE USER IF NOT EXISTS开头,否则 5.7 可能因重复建用户失败(虽然IF NOT EXISTS在 5.7 是被忽略的,但不会报错)
认证插件差异导致 CREATE USER 失败
MySQL 8.0 默认用 caching_sha2_password 插件,而很多老客户端(比如 PyMySQL CREATE USER 'u'@'%' IDENTIFIED BY 'p',8.0 会按默认插件创建用户,结果应用连不上,报错类似 Authentication plugin 'caching_sha2_password' cannot be loaded。
解决办法不是换驱动,而是显式指定插件:
- 兼容旧连接器:
CREATE USER 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'p'; - 注意
IDENTIFIED WITH和IDENTIFIED BY不能混用;BY后面才是密码,WITH后面是插件名 - 如果后续要用
ALTER USER切换插件,得确保用户已存在,否则 5.7 会静默忽略,8.0 则报ERROR 1396 (HY000)
SHOW GRANTS 输出格式变化影响权限解析工具
运维脚本或权限比对工具如果靠正则从 SHOW GRANTS FOR 'u'@'%' 的输出里提取权限,大概率在 8.0 下崩掉。因为 8.0 的输出多了角色行、少了 USAGE 显式声明,且格式不统一。
例如同一用户在 5.7 返回:
GRANT SELECT ON `db`.* TO 'u'@'%'
在 8.0 可能返回:
GRANT SELECT ON `db`.* TO 'u'@'%'<br>GRANT `role_r`@`%` TO 'u'@'%'
问题在于:
-
GRANT `role_r`@`%` TO ...这种行在 5.7 根本不存在,老工具会直接跳过或报错 -
USAGE权限在 8.0 不再显示为完整语句,导致“空权限”误判 - 如果你用
mysqldump --no-data --routines --triggers导出权限,它底层也依赖SHOW GRANTS,同样受此影响
跨版本部署脚本最稳妥的写法
别指望一条语句通吃,CI/CD 流水线往 5.7 测试库和 8.0 生产库同时推初始化 SQL 时,唯一稳的方式是彻底放弃 GRANT ... IDENTIFIED BY 写法。
- 先统一执行:
CREATE USER IF NOT EXISTS 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'p';(5.7 忽略WITH,8.0 按需生效) - 再统一执行纯权限语句:
GRANT SELECT, INSERT ON db.t TO 'u'@'%';(不带任何认证子句) - 避免用
FLUSH PRIVILEGES—— 5.7/8.0 在CREATE USER或GRANT后都自动刷新,手动调用反而可能干扰事务语义 - 如果脚本里有
DROP USER,注意 8.0 下它不级联回收权限,得先REVOKE再DROP,否则残留权限可能引发误授权
真正麻烦的从来不是语法本身,而是那些读取 SHOW GRANTS 输出、靠字符串匹配做权限回滚或审计的工具——它们往往在升级后才暴露问题,而且错误表现很隐蔽。


















