mysql限制指定ip访问需三重闭环:1.用create user 'u'@'ip'绑定精确ip或'ip.%'网段(%非cidr);2.配iptables在链首限3306端口并兜底drop;3.设bind-address+skip_name_resolve防监听与dns干扰。

CREATE USER 必须指定具体 IP 或通配符模式,% 不是限制而是放行;单靠 MySQL 权限无法真正隔离公网访问,必须配合 iptables 和 bind-address 才算闭环。
用 CREATE USER 'u'@'192.168.1.100' 绑定固定 IP
MySQL 的权限匹配基于 User + Host 字符串完全一致,不是子网计算。想只让某台机器连,就写死 IP:
CREATE USER 'app'@'192.168.1.100' IDENTIFIED BY 'pwd';GRANT SELECT ON db.* TO 'app'@'192.168.1.100';- 必须执行
FLUSH PRIVILEGES;,否则新账号不生效 - 如果已有
'app'@'%',得先DROP USER 'app'@'%';,否则客户端可能优先匹配到它 - 测试时用
mysql -h 192.168.1.100 -u app -p,别用localhost——那是 Unix socket,不走 TCP/IP 验证
用 'u'@'192.168.1.%' 模拟 C 段网段(不等于 CIDR)
MySQL 不支持 192.168.1.0/24 这类 CIDR 写法,% 是前缀通配符,不是网络掩码:
免费 DNS 与邮件安全分析(IntoDNS.ai):包括 DNSSEC、SPF、DKIM、DMARC、MTA-STS、BIMI、SMTP STARTTLS、FCrDNS、黑名单、发件人要求及报告。
-
'app'@'192.168.1.%'匹配192.168.1.1到192.168.1.255,但也匹配192.168.1.999(MySQL 静默截断为192.168.1.99) -
'app'@'192.168.%'会匹配192.168.10.5、192.168.100.200,远超预期范围 - 不能对
'app'@'%'执行REVOKE ... FROM 'app'@'192.168.1.%'——权限表里根本没这条记录 - 正确做法是先删旧账号:
DROP USER 'app'@'%';,再建新账号并授权
防火墙必须插在链首且限定端口
MySQL 在 TCP SYN 阶段就响应连接请求,防火墙规则位置或粒度不对,等于没设:
- 错:
iptables -A INPUT -s 192.168.5.0/24 -j DROP——追加在末尾,大概率被前面的ACCEPT放行 - 错:
iptables -I INPUT -s 192.168.5.0/24 -j DROP——没加--dport 3306,会误杀 SSH、HTTP - 对:
iptables -I INPUT -p tcp --dport 3306 -s 192.168.5.0/24 -j ACCEPT+iptables -A INPUT -p tcp --dport 3306 -j DROP - 验证:从非授权 IP 执行
telnet 192.168.5.10 3306应超时或拒绝;若返回Connection refused,说明 MySQL 已响应,防火墙没起作用
bind-address 和 skip_name_resolve 必须协同启用
仅改 bind-address 不等于限制 IP 访问,还要防 DNS 反查干扰:
-
bind-address = 192.168.1.10只监听该内网地址,减少暴露面;但若服务器有多个网卡,仍需确认ss -tlnp | grep :3306输出不含*:3306 -
skip_name_resolve = ON必须启用,否则 MySQL 对客户端 IP 做 DNS 反查,导致延迟、失败,甚至因反解出域名而匹配错Host - 两者缺一不可:不设
bind-address,监听全网口;不设skip_name_resolve,'app'@'192.168.1.%'可能因反解成host.example.com而匹配失败
真正的限制不在 SQL 语句里,而在 iptables 规则是否插在链首、bind-address 是否生效、CURRENT_USER() 返回值是否和你建的账号一致——三者漏一,IP 限制就形同虚设。










