必须使用revoke process on . from 'app'@'%'撤销,process是全局权限,不可作用于数据库或表级;撤销后需重连才生效,且需检查所有host记录并显式撤销grant option和process。

REVOKE PROCESS ON *.* 必须写全,不能省略作用域
PROCESS 权限是全局权限,只能在 *.* 上撤销,写成 db_name.* 或 db_name.table_name 会直接报错:ERROR 1221 (HY000): Incorrect usage of DBACL and GLOBAL PRIVILEGES。MySQL 不允许对非全局对象授予或撤销 PROCESS 权限。
常见错误是误写为:REVOKE PROCESS ON mydb.* FROM 'app'@'%' —— 这条语句语法不合法,执行即失败。
- 正确写法只有这一种:
REVOKE PROCESS ON *.* FROM 'app'@'%' - 主机名必须完全匹配,
'app'@'localhost'和'app'@'%'是两个独立账号,撤销其中一个不影响另一个 - 如果用户有多个 host 记录(比如同时存在
'app'@'10.0.1.%'和'app'@'192.168.1.%'),需逐条执行对应语句
撤销后 SHOW PROCESSLIST 仍可见?检查连接是否重连
执行 REVOKE PROCESS ON *.* FROM 'app'@'%' 成功后,该用户当前已建立的连接仍能执行 SHOW PROCESSLIST —— 因为权限快照在连接建立时已加载,不会动态刷新。
验证方式很简单:让应用重启或手动断开重连,再用该账号登录执行 SHOW PROCESSLIST,此时会报错:ERROR 1227 (42501): Access denied; you need (at least one of) the PROCESS privilege(s) for this operation。
- 连接池场景下尤其容易误判:旧连接还在跑,看起来“权限没撤掉”
- MySQL 8.0+ 可用
SET ROLE NONE;尝试清空当前会话角色缓存,但对 PROCESS 这类全局权限无效,必须重连 - 临时排查可查
SELECT ID, USER, HOST, COMMAND, STATE FROM information_schema.PROCESSLIST WHERE USER = 'app';确认活跃连接来源 host 是否已更新
GRANT OPTION 和 PROCESS 要分开处理
ALL PRIVILEGES 不包含 PROCESS,也不包含 GRANT OPTION。如果你当初是用 GRANT ALL PRIVILEGES ON *.* TO 'app'@'%' 授的权,那么 REVOKE ALL PRIVILEGES ON *.* FROM 'app'@'%' 并不会收回 PROCESS —— 它只撤了标准 DML/DDL 权限,PROCESS 依然挂着。
- 必须显式撤销:
REVOKE PROCESS ON *.* FROM 'app'@'%' - 如果用户还拥有
GRANT OPTION,也要单独撤:REVOKE GRANT OPTION ON *.* FROM 'app'@'%' - 想一次性清干净?写成:
REVOKE ALL PRIVILEGES, GRANT OPTION, PROCESS ON *.* FROM 'app'@'%'
验证是否真失效,别信 “Query OK”
执行完 REVOKE 后立刻运行 SHOW GRANTS FOR 'app'@'%',输出里不该再出现 PROCESS 字样。如果还有,说明要么语句写错了,要么用户在其他 host 上还有残留授权。
注意:USAGE 权限总会存在(表示账号有效但无实际权限),看到 GRANT USAGE ON *.* TO 'app'@'%' 是正常的,不代表 PROCESS 还在。
- 查系统表确认:
SELECT * FROM mysql.user WHERE User = 'app' AND Host = '%'\G,重点看Process_priv列值是否为N - 不要依赖
FLUSH PRIVILEGES:REVOKE 自带权限表更新,加这句不报错但没必要;它只在你手改mysql.user表后才需要 - 真正难的不是写对那条命令,而是搞清这个用户到底在哪几个 host 上被授过 PROCESS —— 漏一个,就还能看到进程列表











