创建用户时须从源头控制风险:限定ip来源(如'192.168.20.%')、强密码(≥12位含大小写字母数字特殊字符)、精确到库表的只读授权,显式回收所有高危权限,并验证无create temporary table、file等越权能力。

创建用户时就限定来源和密码强度
普通用户只读权限不是“先建再锁”,而是从第一步就卡住风险面。比如允许任意IP连接的 'user'@'%',哪怕只给 SELECT,也可能被爆破或撞库——生产环境必须用内网段限制,例如 'reporter'@'192.168.20.%'。密码也不能是弱口令,MySQL 8.0+ 默认启用 validate_password 插件,建议至少含大小写字母、数字、特殊字符,长度 ≥12。
只授权具体库表,禁用 GRANT SELECT ON *.*
全局只读看似省事,实则会暴露 mysql、information_schema、performance_schema 等系统库,攻击者能查账号哈希、权限列表、慢查询日志等敏感信息。正确做法是逐库授权:
GRANT SELECT ON sales_db.* TO 'reporter'@'192.168.20.%'; GRANT SELECT ON analytics_db.fact_orders TO 'reporter'@'192.168.20.%';
如果后续新增库,必须手动补授权,不能图省事开全局。
显式回收高危权限,别信“没授就不带”
MySQL 权限继承机制复杂:旧版本用户可能隐含 USAGE 以外的默认权限;复制环境中 REPLICATION SLAVE 权限可能被误授;甚至某些运维脚本会悄悄加 SUPER。所以必须主动清理:
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, INDEX, LOCK TABLES, EXECUTE ON *.* FROM 'reporter'@'192.168.20.%';REVOKE SUPER, REPLICATION CLIENT, REPLICATION SLAVE, FILE, PROCESS ON *.* FROM 'reporter'@'192.168.20.%';
执行后务必用 SHOW GRANTS FOR 'reporter'@'192.168.20.%'; 确认输出里只有 SELECT 相关行。
验证要覆盖边界场景,不止 INSERT 报错
只测 INSERT 成功与否太表面。真实绕过只读的方式更多:
- 尝试
CREATE TEMPORARY TABLE—— 这不走read_only检查,但若用户有CREATE TEMPORARY TABLES权限,就能构造中间数据 - 执行
SELECT ... INTO OUTFILE—— 若用户有FILE权限,可导出任意可查数据到服务器磁盘 - 连上后跑
SHOW PROCESSLIST;—— 如果没 revokePROCESS,能看到其他用户正在执行的 SQL,包括带密码的连接串
最小权限不是“够用就行”,而是“多一个字节都不给”。只要没明确业务需求,FILE、PROCESS、SHOW VIEW、TRIGGER 全部默认 revoke。










