mysql 8.0 移除了 grant ... identified by 语法,必须拆分为 create user(需显式指定 mysql_native_password 插件)和 grant 两步;alter user identified by 会静默切换为 caching_sha2_password,导致老客户端连接失败。

GRANT 语句里写 IDENTIFIED BY 就报错
MySQL 8.0 直接拒绝解析 GRANT ... IDENTIFIED BY,不是配置问题,是语法层移除。5.7 能跑通的这句:GRANT SELECT ON app.* TO 'api'@'%' IDENTIFIED BY 'p123';,在 8.0 执行会立刻抛出 ERROR 1064 (42000): You have an error in your SQL syntax [...] near 'IDENTIFIED BY'。
必须拆成两步:
CREATE USER 'api'@'%' IDENTIFIED WITH mysql_native_password BY 'p123';GRANT SELECT ON app.* TO 'api'@'%';
注意:如果只写 CREATE USER 'api'@'%' IDENTIFIED BY 'p123';,8.0 默认用 caching_sha2_password 插件,老客户端(如 PyMySQL、PHP mysqli、Navicat ≤12)会连不上,报错 Authentication plugin 'caching_sha2_password' cannot be loaded。
ALTER USER IDENTIFIED BY 会悄悄改认证插件
这是最隐蔽的坑:哪怕用户是用 mysql_native_password 创建的,执行 ALTER USER 'u'@'%' IDENTIFIED BY 'newp'; 后,plugin 字段会被静默覆盖为 caching_sha2_password,导致已有应用突然断连。
查证方式:SELECT user, host, plugin FROM mysql.user WHERE user = 'u';
安全写法始终带插件名:
- 改密码且保留兼容插件:
ALTER USER 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'newp'; - 切回安全插件:
ALTER USER 'u'@'%' IDENTIFIED WITH caching_sha2_password BY 'newp';
SET PASSWORD FOR 在 8.0 已被禁用,执行即报 ERROR 1820。
跨版本初始化脚本怎么写才不炸
想让同一份 SQL 同时在 5.7 和 8.0 运行,别依赖条件判断——MySQL 不支持 SQL 层版本分支。唯一可靠路径是统一用双方都认的语法:
- 用
CREATE USER IF NOT EXISTS开头(5.7 忽略IF NOT EXISTS但不报错,8.0 支持) - 显式指定插件:
CREATE USER IF NOT EXISTS 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'p'; - 后续
GRANT单独执行,不带任何IDENTIFIED子句
避免在脚本里混用 5.7 风格的 GRANT ... IDENTIFIED BY,CI/CD 部署到 8.0 环境时第一条就卡住,排查点往往不在权限逻辑,而在认证插件静默切换。
用户表结构和 SHOW GRANTS 输出也变了
8.0 的 mysql.user 表已移除 password 字段,改用 authentication_string;plugin 默认值从 mysql_native_password 变为 caching_sha2_password。直接 dump 5.7 的 mysql.user 行导入 8.0 会失败。
另外,SHOW GRANTS FOR 'u'@'%' 在 8.0 输出格式不同:多了角色相关行、少了 USAGE 显式声明、字段顺序和引号规则也有差异。靠正则解析该输出的运维工具或权限比对脚本,在 8.0 下大概率失效。
升级后若发现用户连不上,优先查 SELECT user, host, plugin, authentication_string FROM mysql.user;,而不是反复检查 GRANT 语句是否漏了权限。











