应执行SELECT User, Host, Grant_priv, Super_priv FROM mysql.user WHERE Grant_priv = 'Y' OR Super_priv = 'Y'定位高危账号,重点收缩Host为'%'或宽泛网段的账号,并用SHOW GRANTS FOR验证是否含WITH GRANT OPTION,非DBA主账号须立即REVOKE。

查出谁有GRANT OPTION或Super_priv
GRANT OPTION 和 Super_priv 是权限失控的两个关键开关。前者允许用户把权限再授给别人,后者能绕过几乎所有限制(比如 kill 任意连接、改全局变量)。这类账号一旦泄露,等于把整个权限体系交出去。
直接执行这条语句定位高危账号:
SELECT User, Host, Grant_priv, Super_priv FROM mysql.user WHERE Grant_priv = 'Y' OR Super_priv = 'Y';
重点看 Host 字段:如果值是 '%' 或 '10.%' 这类宽泛网段,必须立刻收缩。例如把 'admin'@'%' 改成 'admin'@'192.168.5.100'。
对每个返回的账号,再运行:
SHOW GRANTS FOR 'admin'@'%';
检查输出里是否含 WITH GRANT OPTION —— 除非是 DBA 主账号,否则一律用 REVOKE GRANT OPTION ON *.* FROM 'admin'@'%'; 清掉。
为什么SHOW GRANTS结果不能直接信
SHOW GRANTS FOR 'u'@'h' 只显示显式授予的权限,不反映角色继承、动态权限(MySQL 8.0+)、或通过 PROXY 获得的间接权限。真实生效的权限是叠加结果。
比如你给用户 'app'@'10.20.30.%' 授了角色 'web_writer',但没执行 SET DEFAULT ROLE 'web_writer' TO 'app'@'10.20.30.%';,那登录后实际没权限,而 SHOW GRANTS 默认也不显示角色内容。
要查真实效果,得加 USING 子句:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
SHOW GRANTS FOR 'app'@'10.20.30.%' USING 'web_writer';
或者查系统表:
SELECT * FROM INFORMATION_SCHEMA.ROLE_TABLE_GRANTS WHERE GRANTEE = "'app'@'10.20.30.%'";
GRANT ALL到底给了什么,为什么危险
GRANT ALL ON app_db.* TO 'app'@'%' 看似只给了业务库权限,其实隐含了 CREATE ROUTINE、ALTER ROUTINE、EXECUTE、TRIGGER 等非 DML 权限。这些权限在多数 Web 应用里完全用不到,却可能被 SQL 注入利用来写马、提权。
更隐蔽的是,GRANT ALL 在 MySQL 5.7 中还会自动带上 GRANT OPTION(8.0 已修复),导致权限意外扩散。
正确做法是按需拆解:
GRANT SELECT, INSERT, UPDATE ON app_db.orders TO 'app'@'10.20.30.%';GRANT SELECT ON app_db.products TO 'app'@'10.20.30.%';- 禁用
DROP、ALTER、CREATE、FILE、PROCESS—— 这些基本不该出现在应用账号里
CREATE USER + GRANT 的顺序陷阱(尤其 MySQL 8.0+)
MySQL 8.0 把用户创建和授权彻底拆开。如果还沿用老习惯写 GRANT ALL ON *.* TO 'u'@'h' IDENTIFIED BY 'p';,会直接报错 ERROR 1064 (42000),因为语法已不支持。
但更危险的是“先 CREATE USER,再 GRANT ALL”这种写法:
CREATE USER 'app'@'10.20.30.%' IDENTIFIED BY 'pwd';GRANT ALL ON app_db.* TO 'app'@'10.20.30.%';
问题在于:CREATE USER 后用户已有 USAGE 权限(能连但不能做任何事),但很多人跳过验证,直接 GRANT ALL,结果权限粒度失控。应该在 GRANT 前先确认:
SHOW GRANTS FOR 'app'@'10.20.30.%';
安全起点是只看到 GRANT USAGE ON *.* TO 'app'@'10.20.30.%'。如果不是,说明之前操作残留了权限,得先 REVOKE 再重来。

















