MySQL 不支持 GRANT 语句中用逗号分隔多个用户,须逐条授权或脚本批量生成;WITH GRANT OPTION 仅允许转授自身显式拥有的权限,不支持越权或全局权限;跨主机授权需注意 localhost 与 % 账号独立匹配;REVOKE 会级联清除下游转授权。

MySQL 中一次性授权多个用户要避免用逗号分隔
MySQL 的 GRANT 语句不支持在单条命令里用逗号写多个用户名,比如 GRANT SELECT ON db.* TO 'u1'@'%' , 'u2'@'%' 会直接报错 ERROR 1064 (42000)。必须逐条执行,或用脚本批量生成。
- 正确做法是为每个用户单独写一条
GRANT,例如:GRANT SELECT ON mydb.* TO 'alice'@'localhost'; GRANT SELECT ON mydb.* TO 'bob'@'192.168.1.%'; - 若需批量操作,建议用 shell 或 Python 拼接 SQL:例如用
printf生成多行GRANT,再管道进mysql -u root -p - 注意:每次
GRANT后权限不会自动刷新,但 MySQL 8.0+ 默认立即生效;5.7 及更早版本建议显式执行FLUSH PRIVILEGES(不过只要没改mysql.user表底层,通常也不需要)
WITH GRANT OPTION 不等于“能授任意权限”
授予 WITH GRANT OPTION,只允许被授权者把「自己已拥有的、且显式授予的」权限再转授他人,不能越权、不能授自己没拿到的权限,也不能授全局权限(如 CREATE USER)除非自己也有该权限。
- 例如:
GRANT SELECT, INSERT ON app.* TO 'dev'@'%' WITH GRANT OPTION;→dev可以再给其他人授SELECT或INSERT,但不能授UPDATE,哪怕只对app.* - 如果用户是通过角色(MySQL 8.0+)获得权限,则
WITH GRANT OPTION对角色无效——必须直接授给用户账户 -
GRANT OPTION本身不可继承:A 授 B,B 授 C,C 无法再授 D,除非 B 显式加了WITH GRANT OPTION
跨主机授权时 % 和 localhost 的权限冲突很隐蔽
MySQL 认证时优先匹配最具体的 host,'user'@'localhost' 和 'user'@'%' 是两个完全独立的账号,可能同时存在。常见陷阱是:你给 'app'@'%' 授了权限,但应用连的是本地 socket(触发 localhost 匹配),结果提示 Access denied。
- 检查实际匹配的账号:连接后执行
SELECT USER(), CURRENT_USER();—— 前者是客户端声明的用户 / 主机,后者是服务器最终认证的账号 - 若需统一管理,可删掉
localhost版本:DROP USER 'app'@'localhost';,或确保两个账号权限一致 - 注意:MySQL 8.0 默认安装会创建
'root'@'localhost',它和'root'@'%'无关,不能互相替代
权限委托后 revoke 会级联中断下游授权
用 REVOKE 收回带 WITH GRANT OPTION 的权限时,MySQL 会自动删除所有由该用户转授出去的权限(即级联回收),这是默认行为,不可关闭。
- 例如:
A → GRANT …… TO B WITH GRANT OPTION; B → GRANT …… TO C;,然后REVOKE …… ON …… FROM B;→ C 的权限立刻失效,且SHOW GRANTS FOR C会显示为空 - 没有“仅收回转授权但保留原始权限”的语法;如果想保留 C 的权限,必须先由 A 或其他有权限者重新授给 C
- 回收前建议先用
SELECT * FROM mysql.tables_priv WHERE Grantor = 'B@%';(需有SELECT权限)查清 B 转授了哪些权限,避免误伤
权限委托链越长,后期维护越容易失控;生产环境建议控制在 1 层以内,关键账号尽量由 DBA 直接管理。