MySQL 8.0为什么不能用GRANT自动创建用户

作者:袖梨 2026-08-14

MySQL 8.0 中 GRANT 语句不支持 IDENTIFIED BY,必须拆分为 CREATE USER(显式指定认证插件)和 GRANT 两步执行,否则报 ERROR 1064;用户已存在时应改用 ALTER USER,且需验证插件、角色默认激活及 host 精确匹配。

GRANT语句里写IDENTIFIED BY直接报错

MySQL 8.0 在语法解析阶段就拒绝 GRANT ... IDENTIFIED BY 这种写法,不是权限不够或密码错,而是 parser 根本不认这个结构。你看到的 ERROR 1064 (42000) 就是它——连执行都没走到,更别说建用户了。

常见问题表现:

  1. 执行 GRANT SELECT ON mydb.* TO 'u'@'%' IDENTIFIED BY 'p'; → 立刻报错
  2. 用旧版脚本一键部署,卡在第一条 GRANT 上
  3. 误以为是 root 权限不足,其实 root 也一样被拦

CREATE USER 和 GRANT 各管什么,不能混用

CREATE USER 负责身份认证:用户名、host、密码、认证插件(比如 caching_sha2_passwordmysql_native_password)、密码过期策略;GRANT 只管权限分配,不碰密码、不改插件、不设生命周期。

所以必须分两步:

  1. CREATE USER 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'p';
  2. GRANT SELECT ON mydb.* TO 'u'@'%';

漏掉 IDENTIFIED WITH 就会默认用 caching_sha2_password,老客户端(如某些版本 Navicat、PHP mysqli)连不上,只报 Access denied,根本不会提示插件不匹配。

用户已存在时,别再重试 CREATE USER

如果 CREATE USER 'u'@'%'ERROR 1396 (HY000),说明用户已存在。这时候该用 ALTER USER 改密码,而不是重复执行 CREATE USER

实操建议:

  1. 建用户前加 IF NOT EXISTSCREATE USER IF NOT EXISTS 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'p';
  2. 改密码用 ALTER USER 'u'@'%' IDENTIFIED BY 'new_p';,注意这会把认证插件悄悄重置为默认值
  3. GRANT 后不执行 FLUSH PRIVILEGES 也能生效,但涉及角色默认激活时,SET DEFAULT ROLE 必须显式执行,否则 SHOW GRANTS 看得到绑定,实际查询仍 Access denied

跨版本脚本最容易栽在这三个点上

5.7 脚本能跑,8.0 直接挂,不是因为语法“升级”,而是设计逻辑变了。兼容写法必须避开所有隐式行为:

  1. 删掉所有 GRANT ... IDENTIFIED BY,拆成 CREATE USER + GRANT
  2. CREATE USER 必须显式指定插件,推荐 IDENTIFIED WITH mysql_native_password BY,避免客户端兼容问题
  3. 不要依赖 GRANT ALL PRIVILEGES ON *.* 自动覆盖库级操作——它不等于 GRANT CREATE ON db.*,建表失败往往就卡在这里

真正容易被忽略的,不是怎么写对,而是改完之后没验证认证插件是否真生效、没确认角色是否设了默认激活、也没检查 host 是否精确匹配('u'@'localhost''u'@'127.0.0.1' 是两个用户)。

相关文章

精彩推荐