应执行SHOW GRANTS FOR 'app_user'@'10.20.30.%'查当前生效权限,而非依赖mysql.user表字段;若返回GRANT USAGE ON .,说明仅具连接权;回收权限须严格匹配原授权范围,变更后需新连接验证,必要时用DROP USER彻底注销。

先确认账号当前真实权限,别信mysql.user表
直接查mysql.user表里的Select_priv、Drop_priv字段是错的——这些只是“曾经被设为Y”的痕迹,不代表当前生效权限。比如用户在payment_db上有DROP权限,但你已在该库下用REVOKE DROP ON payment_db.*撤掉,字段仍显示Y,因为全局DROP没动,而MySQL优先走更细粒度的规则。
正确做法是执行:SHOW GRANTS FOR 'app_user'@'10.20.30.%';
它返回的是内存中当前生效的完整权限集合,含角色继承来的权限。如果看到类似GRANT USAGE ON *.* TO ...,说明该账号只保留连接权,没操作权限,这是安全基线。
- 若用户通过角色获得权限,还需查:
SELECT * FROM mysql.role_edges WHERE TO_USER = 'app_user' AND TO_HOST = '10.20.30.%'; - 再对查出的角色执行:
SHOW GRANTS FOR 'role_name'@'%';,确认是否含高危项(如SUPER、FILE) - 没有
SELECT权限?确保你有SELECTonmysql库,否则SHOW GRANTS会报错
回收必须镜像原始GRANT的作用域,否则静默失败
MySQL 的 REVOKE 不是“删掉所有叫 DROP 的权限”,而是“撤销当初用完全相同范围授予的那一项”。比如原始授权是:GRANT DROP, TRUNCATE ON order_db.* TO 'app_user'@'10.20.30.%';,那回收也得写:REVOKE DROP, TRUNCATE ON order_db.* FROM 'app_user'@'10.20.30.%';
常见错误:
— 写成REVOKE DROP ON *.*:语法合法但不生效,因为作用域不匹配
— 写成REVOKE DROP ON order_db.orders:只撤单表,漏了整个库其他表
— 漏掉TRUNCATE:它和DROP权限独立,不撤照样能秒清数据
- 一次性清理结构+数据类高危操作:
REVOKE DROP, TRUNCATE, DELETE ON order_db.* FROM 'app_user'@'10.20.30.%'; - 若原始授权含
GRANT OPTION,必须显式加:REVOKE GRANT OPTION ON order_db.* FROM 'app_user'@'10.20.30.%';(ALL PRIVILEGES不含它) - 全局权限如
RELOAD、PROCESS只能用ON *.*,写ON app_db.*会直接报错
权限变更后旧连接仍有效,必须验证重连
执行完REVOKE,立刻用原连接测试DROP TABLE成功?不是命令失效,是你还在用缓存权限的旧会话。MySQL 权限检查发生在连接建立时,已建立的连接不会自动刷新。
- 验证是否真生效:新开一个连接,例如
mysql -u app_user -p -h db-host -P 3306 - 应用端用连接池(如 HikariCP、Druid)?需重启服务或调用
evict()清空池中所有连接 - 不想等超时断开?手动查并杀掉残留连接:
SELECT id, user, host FROM information_schema.processlist WHERE user = 'app_user';→KILL <id>;</id> - 云平台(如阿里云 RDS)可能有权限同步延迟,执行后等 30 秒再验证
彻底回收别只靠REVOKE,DROP USER才是终极方案
如果账号已离职或长期不用,REVOKE只是“卸武器”,DROP USER才是“注销身份”。它会从mysql.user、mysql.db、mysql.role_edges等所有权限表中物理删除记录,连带角色绑定、SSL设置、资源限制一并清除。
但要注意三个硬约束:
— 若该用户是某存储过程的DEFINER,DROP USER会失败,报错ERROR 3725 (HY000),需先改定义者或删对象
— 正有活跃连接?DROP USER会立即断开,可能触发应用重连风暴,建议业务低峰期操作
— 中间件(如 ProxySQL)或配置文件里硬编码了该用户名?删完后应用报Unknown user而非权限拒绝,排查路径变长
- 安全起见,先锁定账号再评估:
ALTER USER 'app_user'@'10.20.30.%' ACCOUNT LOCK; - 确认无依赖后执行:
DROP USER 'app_user'@'10.20.30.%'; - 最后一步常被跳过:检查
information_schema.SCHEMATA或SHOW DATABASES,确认该用户无法再看到任何业务库名(USAGE权限被移除后,SHOW DATABASES只返回information_schema)


















