MySQL访问控制核心是mysql.user表中host字段的匹配规则,而非防火墙或bind_address;需结合bind_address限制监听、host限定用户来源、防火墙/安全组控制网络层访问,并避免直接UPDATE权限表。
MySQL 的访问控制核心不在防火墙或配置文件,而在于 mysql.user 表中每个用户的 host 值。它不是“白名单开关”,而是连接匹配规则:客户端发起连接时,MySQL 会按 user@host 组合逐行匹配权限表,取最具体的匹配项(比如 'app'@'192.168.1.100' 优先于 'app'@'%')。
常见误区是以为改了 bind_address 或开了防火墙就等于限制了 IP —— 实际上只要用户被建为 'user'@'%',且密码正确,任何能连到 MySQL 端口的 IP 都能登录。
CREATE USER 'api'@'10.0.5.22' 明确指定单 IP,或 'report'@'192.168.10.%' 匹配子网
GRANT ... ON *.* TO 'admin'@'%',生产环境应限定 hostSELECT User, Host FROM mysql.user WHERE Host = '%';
RENAME USER 'old'@'%' TO 'old'@'172.16.3.45';(注意:不能直接 UPDATE 表,必须用 RENAME 或 DROP+CREATE)bind_address 控制 mysqld 进程绑定哪个网卡地址,默认值 127.0.0.1 意味着只接受本地 socket 或 localhost TCP 连接,外部 IP 根本连不上 —— 这是最基础的网络层隔离,比账号 host 更前置。
若需允许远程访问,必须显式设为 0.0.0.0(所有 IPv4 接口)或具体内网 IP(如 192.168.2.10),但此时务必配合严格的 user@host 策略,否则等于裸奔。
bind_address = 192.168.2.10,并确保防火墙放行该 IP 的 3306 端口
skip-networking = 1,适合纯本地应用,但
mysql -h 127.0.0.1 会失败(走 TCP),必须用 -S /var/run/mysqld/mysqld.sock
bind_address = :: 同时监听 IPv6,若只需 IPv4,别写成 0.0.0.0,::,否则可能绕过预期限制MySQL 自身不校验来源 IP 的合法性,host 字段只是权限匹配依据;真实网络流量是否抵达 mysqld,取决于操作系统防火墙和云厂商安全组。两者缺一不可。
例如:你已将用户设为 'web'@'10.0.1.,但服务器防火墙未开放 3306 端口,或阿里云安全组没放行该 IP,连接仍会超时(而非报错 “Access denied”)。
5'
iptables -A INPUT -p tcp --dport 3306 -s 10.0.1.5 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP
10.0.1.5/32)telnet db-host 3306 看端口通不通,再尝试 mysql 客户端登录 —— 区分是网络层拦截还是权限层拒绝修改 mysql.user 表(如 INSERT/UPDATE/DELETE)后,必须执行 FLUSH PRIVILEGES; 才能让变更生效。但使用 CREATE USER、GRANT、DROP USER 等 DDL 语句时,MySQL 会自动重载权限表,无需手动 flush。
容易踩坑的是:有人用 UPDATE mysql.user SET Host='10.0.1.5' WHERE User='app'; 改完不 flush,结果权限一直不生效,还以为是语法或缓存问题。
FLUSH PRIVILEGES;
authentication_string 加密方式、password_expired 状态),推荐始终用 GRANT/REVOKE实际部署中最容易被忽略的,是 bind_address 和 user@host 的双重约束关系 —— 少一个环节,整个白名单就形同虚设。