GRANT ALL PRIVILEGES本身不包含GRANT OPTION,必须显式添加WITH GRANT OPTION才能赋予转授权限;MySQL 8.0+需分步执行CREATE USER和GRANT,且GRANT OPTION仅在其对应权限作用域内生效。

GRANT ALL不带WITH GRANT OPTION,用户就真没授予权限
MySQL里GRANT ALL PRIVILEGES本身不包含GRANT OPTION——哪怕你用root执行,也得显式加WITH GRANT OPTION,否则被授权用户无法再转授权限。这不是疏忽,是MySQL的权限模型设计:授予权限(grant)和使用权限(比如SELECT/INSERT)是两套独立开关。
常见错误现象:SHOW GRANTS FOR 'user'@'host'里看不到GRANT OPTION;该用户执行GRANT SELECT ON db.* TO ...直接报错ERROR 1045 (28000): Access denied。
-
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;✅ 正确(全局+转授权) -
GRANT ALL PRIVILEGES ON db.* TO 'user'@'localhost' WITH GRANT OPTION;✅ 正确(库级+转授权) -
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%';❌ 没有WITH GRANT OPTION,用户不能GRANT
MySQL 8.0+必须分两步:CREATE USER + GRANT,不能再合并在一条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;(虽然多数情况下非必需,但保险起见建议执行)
WITH GRANT OPTION只对当前GRANT语句作用域生效
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不会自动合并——每个作用域单独判断
检查和验证GRANT OPTION是否生效,别只信“执行成功”
命令返回Query OK不代表权限已落地。尤其当用户已登录并复用连接时,新权限可能未加载。最可靠验证方式是切换上下文检查:
- 用高权限账号执行:
SHOW GRANTS FOR 'u'@'%';—— 看输出里有没有GRANT OPTION字样 - 用目标用户重新登录:
mysql -u u -p,然后执行SELECT CURRENT_USER();确认身份无误 - 尝试一次最小化转授:
GRANT SELECT ON test.* TO 'dummy'@'localhost';,看是否报错
容易忽略的一点:如果用户是通过'u'@'192.168.%'和'u'@'%'两个host定义的,而你只给其中一个加了WITH GRANT OPTION,那实际生效的是匹配度最高的那个host条目——查mysql.user表确认具体行。


















