mysql用户必须显式创建为'username'@'host'完整形式,如'app'@'192.168.1.%',不可省略host;host不匹配则直接拒绝连接,grant也须完全一致,否则权限错配或失效。

CREATE USER 必须显式写全 'user'@'192.168.1.%',不能省略 @'host'
MySQL 的用户账号是 user@host 二元组,host 字段不匹配就直接拒绝连接,不会 fallback 到其他记录。如果你执行 CREATE USER 'app' IDENTIFIED BY 'pwd';,MySQL 默认创建的是 'app'@'%',权限范围过大,且后续 GRANT 若没写全 @'192.168.1.%',很可能授错对象。
正确做法是:
- 用单引号包裹 host 值,如
'192.168.1.%'(不是192.168.1.*,*不是 MySQL 通配符) - 避免漏引号导致语法错误,例如
'app'@192.168.1.%是非法的 - 确认目标网段是否真实存在——
'10.0.2.%'和'192.168.1.%'是完全不同的匹配规则
GRANT 的 host 必须和 CREATE USER 完全一致
授权不是“追加到用户”,而是绑定到某条具体的 user@host 记录。如果你先建了 'app'@'192.168.1.%',但写 GRANT SELECT ON mydb.* TO 'app';,MySQL 会默认解释为 'app'@'%',结果就是新用户没权限、旧用户反而被误授。
务必核对两处 host 是否一模一样:
- 运行
SELECT User, Host FROM mysql.user WHERE User = 'app';确认目标记录存在且Host值是你期望的 -
GRANT SELECT, INSERT ON mydb.* TO 'app'@'192.168.1.%';中的字符串必须逐字相同 - 执行完立刻
FLUSH PRIVILEGES;,否则权限不生效
bind-address 和防火墙必须与 host 粒度对齐
即使用户权限设成 'app'@'192.168.1.%',如果 MySQL 没监听对应网卡,连接请求根本进不来。常见错配:
-
bind-address = 127.0.0.1→ 只收本地请求,远程 IP 再匹配也连不上 -
bind-address = 0.0.0.0+'app'@'192.168.1.%'→ 安全,但要求客户端真实出口 IP 在该网段(NAT 后可能变形) -
bind-address = 192.168.1.100+'app'@'192.168.1.%'→ 更精准,避免暴露到公网接口 - Linux 防火墙:运行
sudo ufw allow from 192.168.1.0/24 to any port 3306 - 云平台安全组:入方向规则源 CIDR 设为
192.168.1.0/24,不是0.0.0.0/0
ERROR 1130 就是 host 不匹配,别瞎查网络配置
当看到 ERROR 1130 (HY000): Host 'x.x.x.x' is not allowed to connect to this MySQL server,第一反应不是改防火墙或重装驱动,而是检查账号是否存在且 Host 字段是否精确匹配。
排查步骤:
- 用管理员登录后执行
SELECT User, Host FROM mysql.user;,看有没有'app'@'192.168.1.%'这条记录 - 确认连接时用的 IP 是否真在该网段内(比如 NAT 后变成 100.64.x.x,就匹配不上
192.168.1.%) - 注意
'app'@'localhost'和'app'@'127.0.0.1'是两个账户,前者走 Unix socket,后者走 TCP,别漏掉其中一个 - 已有用户想收紧权限,不要
UPDATE mysql.user,用DROP USER 'app'@'%';再重建,或RENAME USER 'app'@'%' TO 'app'@'192.168.1.%';
实际部署时最容易被忽略的是:MySQL 的 % 通配符不支持 CIDR,'192.168.1.%' 会静默匹配 192.168.1.1234 这类非法地址,它只是字符串前缀匹配,不是子网计算。真正严格的网段控制得靠防火墙或云安全组兜底。











