mysql中设置访问控制与IP白名单配置

来源:这里教程网 时间:2026-02-28 20:37:48 作者:

MySQL 用户账户的 host 字段决定能否从指定 IP 连接

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'@'%'
,生产环境应限定 host
检查现有宽松账户:
SELECT User, Host FROM mysql.user WHERE Host = '%';
修改已有用户 host:
RENAME USER 'old'@'%' TO 'old'@'172.16.3.45';
(注意:不能直接 UPDATE 表,必须用 RENAME 或 DROP+CREATE)

mysqld 配置中的 bind_address 和 skip-networking 影响监听范围

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 端口
完全禁用 TCP(仅 socket):
skip-networking = 1
,适合纯本地应用,但
mysql -h 127.0.0.1
会失败(走 TCP),必须用
-S /var/run/mysqld/mysqld.sock
IPv6 注意:
bind_address = ::
同时监听 IPv6,若只需 IPv4,别写成
0.0.0.0,::
,否则可能绕过预期限制

防火墙与云平台安全组是必要补充,不是替代方案

MySQL 自身不校验来源 IP 的合法性,

host
字段只是权限匹配依据;真实网络流量是否抵达 mysqld,取决于操作系统防火墙和云厂商安全组。两者缺一不可。

例如:你已将用户设为

'web'@'10.0.1.5'
,但服务器防火墙未开放 3306 端口,或阿里云安全组没放行该 IP,连接仍会超时(而非报错 “Access denied”)。

Linux iptables 示例(仅允特定 IP):
iptables -A INPUT -p tcp --dport 3306 -s 10.0.1.5 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP
云平台操作重点:确认安全组规则作用在**数据库实例所在服务器的网卡**,而不是跳板机或 LB;入方向规则目标端口填 3306,源地址填 CIDR(如
10.0.1.5/32
测试连通性顺序:先
telnet db-host 3306
看端口通不通,再尝试 mysql 客户端登录 —— 区分是网络层拦截还是权限层拒绝

动态刷新权限后记得 flush privileges,但多数情况不需要

修改

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,结果权限一直不生效,还以为是语法或缓存问题。

安全起见,执行完 DML 类权限修改后,加一句:
FLUSH PRIVILEGES;
避免直接 UPDATE 权限表:字段逻辑复杂(如
authentication_string
加密方式、
password_expired
状态),推荐始终用 GRANT/REVOKE
权限变更对已建立连接无效:新权限只影响后续新连接,当前连接维持原有权限直到断开

实际部署中最容易被忽略的,是

bind_address
user@host
的双重约束关系 —— 少一个环节,整个白名单就形同虚设。

相关推荐