直接执行GRANT ALL PRIVILEGES等同于交出数据库root密钥,导致误删库、勒索加密、横向渗透等高危风险;必须拆分CREATE USER与GRANT步骤,显式限定host、密码策略及SSL要求,并逐表精确授权、显式回收DROP/ALTER/FILE等高危权限。

直接执行GRANT ALL PRIVILEGES会触发什么风险
这不是权限“够用”的问题,而是等同于把数据库的 root 密钥交出去。一旦该账号泄露或被注入,攻击者能 DROP DATABASE、CREATE USER、LOAD DATA INFILE,甚至通过 FILE 权限写入 Webshell。生产环境里,90% 的数据误删、勒索加密、横向渗透都始于一个被滥授 ALL PRIVILEGES 的应用账号。
创建账号时必须拆开 CREATE USER 和 GRANT 两步
MySQL 8.0+ 已弃用隐式建户(即用 GRANT 同时建用户),且容易漏掉密码策略、SSL 要求、IP 限制等关键安全项。直接 GRANT SELECT ON *.* TO 'app'@'%' 不仅语法过时,还可能报错 ERROR 1410 (42000): You are not allowed to create a user with GRANT。
- 先显式建户:
CREATE USER 'app_user'@'10.20.30.%' IDENTIFIED BY 'strong_pass_2024' REQUIRE SSL PASSWORD EXPIRE INTERVAL 90 DAY; - 再精确授权:
GRANT SELECT, INSERT, UPDATE ON myapp_db.users TO 'app_user'@'10.20.30.%'; - 立刻回收高危权限:
REVOKE DROP, ALTER, CREATE, FILE, SUPER ON *.* FROM 'app_user'@'10.20.30.%';(哪怕没授过,显式回收更稳妥)
如何快速发现已存在的 ALL PRIVILEGES 账号
权限是叠加生效的,mysql.user 表里的 Super_priv='Y' 或 Grant_priv='Y' 就代表事实上的全权控制。别信“这个账号只读”,得查真实权限。
- 运行这句找出高危账号:
SELECT User, Host, Super_priv, Grant_priv FROM mysql.user WHERE Super_priv='Y' OR Grant_priv='Y'; - 重点关注
Host是%或宽泛网段(如10.%)的记录 —— 它们极可能被远程利用 - 对返回结果中的每个账号,补查:
SHOW GRANTS FOR 'user'@'host';,确认是否真有ALL PRIVILEGES或跨库操作权
权限必须精确到库+表,禁用通配符 *
ON *.* 和 ON myapp_db.* 看似只差一层,但后者仍允许对库内任意表执行 DROP TABLE —— 只要没显式 REVOKE DROP。真正的最小权限,是锁定到具体表名。
- Web 应用通常只需:
GRANT SELECT, INSERT, UPDATE ON myapp_db.orders TO 'web_user'@'10.20.30.%'; - 报表服务只读场景:
GRANT SELECT ON myapp_db.reports_view TO 'report_user'@'10.20.30.%'; - 绝对避免:
GRANT ALL PRIVILEGES ON myapp_db.* TO ...、GRANT SELECT ON *.* TO ... - 若需多表,逐条授权,不偷懒用通配符;表结构变更时,同步检查并更新权限
真正卡住 ALL PRIVILEGES 的不是命令写法,而是权限设计流程:新账号上线前,必须根据应用 SQL 日志反推最小集,而不是“先给全权,出问题再收”。多数越权事故,发生在第一次部署时没人看日志、没人问“它到底要查哪张表”。


















