MySQL 8.0+禁止GRANT中使用IDENTIFIED BY,否则触发ERROR 1064;必须先CREATE USER设密码,再GRANT授予权限,且库名含数字或特殊字符时须用反引号包裹。

GRANT 语句里写了 IDENTIFIED BY 就会报 ERROR 1064
MySQL 8.0+ 的 SQL 解析器直接移除了 GRANT ... IDENTIFIED BY 这个语法路径,不是拼写错了、也不是权限不够,而是整条语句结构不合法。你写的这句:
GRANT SELECT ON mydb.* TO 'u'@'%' IDENTIFIED BY 'pwd';
在 8.0+ 环境下必然触发 ERROR 1064 (42000),错误位置通常标在 IDENTIFIED BY 附近。
原因很实在:用户身份(密码、认证插件)和权限分配被强制拆成两个原子操作。CREATE USER 负责建人设密,GRANT 只管授什么权、在哪生效。
- 想兼容旧脚本?别改语法,改流程:先
CREATE USER,再GRANT - 用户已存在?重跑
CREATE USER会报ERROR 1396,该换ALTER USER 'u'@'%' IDENTIFIED BY 'newpwd' - 执行完建议补一句
FLUSH PRIVILEGES,尤其在批量操作或跨客户端场景下,避免权限延迟生效
库名含数字或中划线时没加反引号
MySQL 对数据库名解析很严格:如果库名是纯数字(比如 12345)、含中划线(my-db)、或撞上关键字(order),不加反引号就直接报语法错。
错误写法:
GRANT SELECT ON 12345.* TO 'u'@'%';
正确写法必须用英文反引号(Esc 下面那个键,不是单引号):
GRANT SELECT ON `12345`.* TO 'u'@'%';
或者:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
GRANT SELECT ON `my-db`.* TO 'u'@'%';
- RDS、PolarDB、本地 MySQL 全都遵循这条规则,不能省
- 表名、列名同理,只要带特殊字符或数字开头,就得包
` - 用
SHOW DATABASES;看到的库名,复制过来也得手动加反引号
WITH GRANT OPTION 没显式声明,但你以为它默认有
GRANT ALL PRIVILEGES 本身不带转授权限——哪怕你是 root 执行的,被授权用户也执行不了任何 GRANT 语句,一试就报 ERROR 1045。
检查是否生效最直接的方法是运行:
SHOW GRANTS FOR 'u'@'%';
如果输出里没出现 GRANT OPTION,那就真没开。
- 要全局转授:用
GRANT ALL PRIVILEGES ON *.* TO 'u'@'%' WITH GRANT OPTION - 只允许在某库内转授:用
GRANT SELECT, INSERT ON `app_db`.* TO 'u'@'localhost' WITH GRANT OPTION -
WITH GRANT OPTION不会跨语句合并——每个GRANT单独绑定作用域,不能靠“多执行几次”来叠加
认证插件不匹配导致连接卡住,但你以为是 GRANT 报错
语法全对、CREATE USER 和 GRANT 都成功了、FLUSH PRIVILEGES 也执行了,结果应用连不上,报 Access denied 或卡在 Authenticating...——大概率是 caching_sha2_password 插件惹的祸。
MySQL 8.0 默认用这个插件,但老版 JDBC 5.x、PyMySQL、PHP mysqli、Navicat 12 以下都不支持它。这不是权限问题,是连接握手阶段就断了。
- 创建用户时就指定兼容插件:
CREATE USER 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd' - 用
ALTER USER改密时也要写全:ALTER USER 'u'@'%' IDENTIFIED WITH mysql_native_password BY 'newpwd',否则插件会被悄悄重置为默认值 - 别指望 SET PASSWORD,MySQL 8.0 已禁用,执行即报
ERROR 1820
最容易忽略的是:这个点不报语法错误,也不阻断 SQL 执行,但它会让应用死在第一步连接上——排查时得从用户创建起就盯紧插件策略。










