GRANT ALL PRIVILEGES 不包含 GRANT OPTION,需显式添加 WITH GRANT OPTION 才能授予权限;MySQL 8.0+ 必须先 CREATE USER 再 GRANT,且 GRANT OPTION 严格限定于对应权限范围。

GRANT ALL 不等于有 GRANT OPTION
这是最常被误解的一点:GRANT ALL PRIVILEGES 本身**不包含** GRANT OPTION。哪怕你是 root,执行了 GRANT ALL ON *.* TO 'u'@'%',该用户依然无法执行任何 GRANT 语句——因为授予权限(grant)和使用权限(如 SELECT/INSERT)在 MySQL 中是两套独立开关。
常见错误现象:
-
SHOW GRANTS FOR 'u'@'%'输出里没有WITH GRANT OPTION - 用户执行
GRANT SELECT ON db.* TO 'other'@'localhost'直接报错ERROR 1045 (28000): Access denied
解决办法:必须显式加上 WITH GRANT OPTION,例如:
GRANT ALL PRIVILEGES ON *.* TO 'u'@'%' WITH GRANT OPTION;
注意:这个选项只对当前语句中指定的权限范围生效,不是全局开通“能授一切权”。
MySQL 8.0+ 必须分步创建用户和授权
在 MySQL 8.0 及以上版本,GRANT ... IDENTIFIED BY 语法已被彻底移除。如果你还沿用老写法:
GRANT ALL ON *.* TO 'u'@'%' IDENTIFIED BY 'pwd' WITH GRANT OPTION;
会立刻触发 ERROR 1064 (42000),提示语法错误。
正确流程只有两步(缺一不可):
- 先创建用户:
CREATE USER 'u'@'%' IDENTIFIED BY 'pwd'; - 再赋权:
GRANT ALL PRIVILEGES ON *.* TO 'u'@'%' WITH GRANT OPTION; - 最后建议执行:
FLUSH PRIVILEGES;(虽多数情况自动刷新,但保险起见)
漏掉 CREATE USER 或合并写法,都会导致授权失败,且错误信息容易误导你去查权限而非语法。
GRANT OPTION 的作用域很窄
WITH GRANT OPTION 不是“永久开通授予权”,它严格绑定在当前 GRANT 语句的权限范围上。比如:
GRANT SELECT, INSERT ON app_db.* TO 'dev'@'localhost' WITH GRANT OPTION;
那么 dev 只能将 SELECT 和 INSERT 权限授予别人,且仅限于 app_db 下的表——他不能授 UPDATE,也不能授 mysql.user 表的任何权限。
想让某用户能授予任意权限?必须给:
-
ALL PRIVILEGES ON *.*+WITH GRANT OPTION - 只给某个库的
GRANT OPTION,但忘了CREATE或DROP?那他在转授时仍会被拒绝(权限不足) - 用户从多个
GRANT语句获得权限?GRANT OPTION不会自动合并——每个作用域单独判断
root 执行 GRANT 失败?先看 read_only 和 skip_grant_tables
即使你是 root,执行 GRANT 报 ERROR 1290 (HY000),大概率是以下两种配置挡住了:
-
SELECT @@read_only;返回1→ 服务器启用了只读模式,需SUPER权限才能关:SET GLOBAL read_only = OFF;,或改配置文件后重启 -
SELECT @@skip_grant_tables;返回1→ 权限系统根本没加载,所有GRANT、ALTER USER都被禁用。必须编辑my.cnf注释掉skip-grant-tables并重启服务
这两个状态常被忽略,尤其重置密码后忘记清理配置。检查完再折腾权限,能省下大半排查时间。


















