grant all privileges 不包含 with grant option,必须显式添加才能转授;mysql 8.0+ 需先 create user 再 grant,且 with grant option 严格绑定权限范围与作用域。

GRANT ALL PRIVILEGES 不等于有 GRANT OPTION,必须显式加上 WITH GRANT OPTION 才能转授。
为什么 GRANT ALL 不能自动带授予权限?
MySQL 把“使用权限”和“授予权限”拆成两套独立开关。哪怕你执行了 GRANT ALL PRIVILEGES ON *.* TO 'u'@'%',SHOW GRANTS FOR 'u'@'%' 输出里也绝不会出现 WITH GRANT OPTION —— 因为它根本没被开启。
常见错误现象:
- 用户执行
GRANT SELECT ON db.* TO 'other'@'localhost'直接报错ERROR 1045 (28000): Access denied -
SHOW GRANTS结果里没有WITH GRANT OPTION字样
解决办法只有一条:重写授权语句,显式带上 WITH GRANT OPTION:
GRANT ALL PRIVILEGES ON *.* TO 'u'@'%' WITH GRANT OPTION;
注意:WITH GRANT OPTION 只对当前语句中指定的权限范围生效,不是全局开通“能授一切权”。
MySQL 8.0+ 必须先 CREATE USER 再 GRANT
在 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;(尤其在直连 socket 或权限缓存延迟时)
漏掉 CREATE USER 或合并写法,都会导致授权失败,且错误信息容易误导你去查权限而非语法。
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语句获得权限?GRANT OPTION不会自动合并,每个作用域单独判断 - 只给了
SELECT权限 +WITH GRANT OPTION,但对方想授CREATE?会被拒绝(权限不足) - Host 不匹配:
'u'@'localhost'和'u'@'127.0.0.1'是两个完全独立账户,SHOW GRANTS查不到就说明用户根本不存在
最常被忽略的一点是:权限变更后不检查 SHOW GRANTS 输出是否真含 WITH GRANT OPTION,而只信“命令执行成功”。实际中,GRANT 成功不代表 GRANT OPTION 已生效,必须人工确认。











