‘%’主机名比弱口令更危险,因其直接向任意IP开放访问权限,无需爆破即可利用;弱口令需被猜中才能入侵,而‘%’使强密码也形同虚设,两者叠加导致90%的MySQL拖库事件。

弱口令 + '%' Host 组合,等于把数据库的钥匙塞进快递柜还贴了张“随便取”的纸条——90% 的 MySQL 拖库事件都源于这两点同时存在。
为什么 '%' 主机名比弱口令更危险
弱口令需要被猜中或爆破才能利用;而 '%' 是直接敞开大门,只要知道账号密码(哪怕密码是强的),攻击者从任意 IP 都能连进来。MySQL 用户身份由 'user'@'host' 共同决定,'root'@'%' 和 'root'@'localhost' 是两个完全独立的账号,权限互不影响。
- MySQL 5.7+ 虽默认禁用
root'@'%',但你CREATE USER 'app'@'%'时它照常生效 - 云环境有安全组 ≠ MySQL 层可放任
'%':安全组配错、临时开放、跳板机绕过都很常见 - 容器环境用
'172.18.0.%'看似合理,但如果该子网混有测试/CI 容器,就等于把权限分给了不可信节点
如何批量清理和替换现有 '%' 账号
别直接 DROP USER 所有 '%' 账号——有些可能是监控、备份脚本在用。先查、再判、后改。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查所有通配主机账号:
SELECT User, Host FROM mysql.user WHERE Host = '%'; - 查具体权限分布:
SHOW GRANTS FOR 'dev'@'%';,重点看是否含GRANT OPTION或*.*权限 - 对确认废弃的账号,执行:
DROP USER 'dev'@'%';(MySQL 5.7+ 支持,无需先REVOKE) - 对需保留的业务账号,重建为精确 IP:
CREATE USER 'api_user'@'192.168.20.55' IDENTIFIED BY 'StrongP@ss2026!'; - 重授最小权限:
GRANT SELECT, INSERT ON order_db.orders TO 'api_user'@'192.168.20.55';,绝不用ALL PRIVILEGES
弱口令必须配合插件强制拦截,不能只靠人工提醒
仅靠 DBA 命令 SET PASSWORD 改密码,下一次开发提需求时又会回到 '123456'。必须启用密码验证插件,让 MySQL 自己拒绝弱密码。
- 检查是否已加载:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'validate%'; - 未启用则安装:
INSTALL PLUGIN validate_password SONAME 'validate_password.so'; - 设策略等级(推荐 MEDIUM):
SET GLOBAL validate_password.policy = MEDIUM; - 关键参数建议:
validate_password.length = 12,validate_password.mixed_case_count = 2,validate_password.number_count = 2 - 注意:该插件对已有弱密码不追溯,只拦截新设/修改密码行为
最容易被忽略的“隐性 '%'”场景
你以为自己没写 '%',但某些操作会悄悄引入等效风险:
-
GRANT ... TO 'user'@'':空 Host 字符串在部分旧版本中等价于'%',务必用SELECT User, Host FROM mysql.user检查是否存留 - 使用
mysql_secure_installation时选了“允许 root 远程登录”,它会自动创建'root'@'%'——这个步骤必须手动否决 - 某些 ORM 框架连接字符串里写
host=0.0.0.0,应用层虽不直接建用户,但若 DB 监听0.0.0.0:3306且账号 Host 是'%',效果一样 - MySQL 8.0+ 的角色(Role)本身不绑定 Host,
GRANT role_name TO 'user'@'%'依然危险——角色只是权限集合,Host 控制权仍在用户定义层










