必须先查mysql.role_edges表确认绑定角色,再逐个执行revoke 'role_name' from 'user'@'host';撤销后用户仍保留usage权限,需额外revoke usage on .才能彻底禁连。

查清用户绑定了哪些角色
直接执行 SHOW GRANTS FOR 'user'@'host' 看不到角色是否实际生效,它只显示历史授予语句。真正权威的来源是系统表 mysql.role_edges。
运行这条查询确认绑定关系:SELECT FROM_USER FROM mysql.role_edges WHERE TO_USER = 'user' AND TO_HOST = 'host';
- 返回空结果,说明该用户没被授过任何角色,跳过后续撤销步骤
- 返回多行,每行
FROM_USER值就是你要在REVOKE中用的角色名(含大小写、下划线) - 如果用户有多个 host 变体(如
'user'@'192.168.%'和'user'@'%'),必须分别查、分别处理
逐个执行 REVOKE 'role_name' FROM 'user'@'host'
MySQL 8.0 不支持批量解绑或模糊语法,必须对每个查出的角色名,显式写出完整语句。
例如查到用户 'alice'@'localhost' 绑定了 dev_role 和 reader_role,就得执行两遍:
REVOKE 'dev_role' FROM 'alice'@'localhost';REVOKE 'reader_role' FROM 'alice'@'localhost';
- 角色名和用户名都必须用单引号包裹
- 主机名必须完全一致——
'alice'@'%'对'dev_role'执行REVOKE,但该角色实际绑定在'alice'@'localhost'上,语句会静默成功,但不生效 - 不存在
REVOKE ALL FROM 'alice'@'localhost'这种语法,执行必报ERROR 1064 (42000)
撤销后用户仍保留 USAGE 权限
角色解绑完成后,用户还能正常连接 MySQL,但所有 DML/DQL/DDL 操作都会触发 ERROR 1044 (42000) 或 ERROR 1227 (42000) ——这不是失败,而是预期状态。
这是因为 MySQL 默认保留 USAGE ON *.*,仅允许登录,不赋予任何操作权。
- 若需彻底禁连,必须额外执行:
REVOKE USAGE ON *.* FROM 'alice'@'localhost'; - 漏掉这一步,容易误判“权限已回收”,其实用户仍可建立连接并执行
SELECT VERSION()这类极低权限操作 -
REVOKE USAGE ON *.*不能省略ON *.*,否则语法错误
别混淆 REVOKE 和 DROP ROLE
REVOKE 'role_name' FROM 'user'@'host' 只解除绑定,不影响角色定义本身;DROP ROLE 'role_name' 是删掉角色及其所有内置权限。
- 想让某个用户失去权限 → 用
REVOKE解绑 - 想让整个角色失效且确认无其他用户在用 → 先
REVOKE所有绑定,再DROP ROLE - 对已绑定角色的用户执行
DROP ROLE会报ERROR 3530 (HY000),必须先解绑
角色绑定是显式边关系,不是自动刷新的快照。撤销动作本身很简单,但查准、写准、补全 USAGE 处理,才是真实运维中容易卡住的地方。











