MySQL用户账号绑定IP需精确匹配host字段,如'api'@'192.168.5.11';不支持CIDR,%仅作字符通配;须删除冗余宽泛权限、检查bind-address与防火墙、区分localhost与127.0.0.1。

mysql用户账号绑定具体IP地址
MySQL的权限系统靠 user@host 这个组合来识别访问来源,host 部分不是“允许范围”,而是“必须完全匹配”的主机标识。想只让内网某台机器连,就得把 host 写成它的实际IP,比如 'app-server'@'192.168.10.42'。
常见错误是写成 'user'@'192.168.%' 或 'user'@'192.168.10.0/24' —— MySQL不支持CIDR掩码,% 是通配符但只匹配任意字符(不含点号分隔的段数逻辑),192.168.% 实际会匹配 192.168.100.200 甚至 192.168x.y,非常危险。
- 创建账号时直接指定IP:
CREATE USER 'api'@'192.168.5.11' IDENTIFIED BY 'pwd123'; - 已有账号需用
RENAME USER或先DROP USER再重建,不能只改host - 执行完记得
FLUSH PRIVILEGES;,否则变更不生效
为什么GRANT后还是连不上?检查host字段是否被覆盖
MySQL在权限匹配时,会按 user@host 字符串长度由长到短排序匹配,最长的优先。如果同时存在 'app'@'192.168.5.%' 和 'app'@'192.168.5.11',而前者权限更大,那么即使你从 192.168.5.11 连入,也会命中前者——导致你以为绑定了IP,实际走的是宽泛规则。
- 查当前所有匹配该用户的记录:
SELECT User, Host FROM mysql.user WHERE User = 'app'; - 删掉冗余的宽泛条目,比如
'app'@'%'或'app'@'192.168.%' - 确认连接时客户端真实出口IP:容器里可能看到的是网关IP,K8s Pod可能经过Service代理,得看
SHOW PROCESSLIST;里的Host列
bind-address和防火墙是两层控制,缺一不可
bind-address 是MySQL服务监听的网卡地址,不是权限控制手段。设成 127.0.0.1 就只能本地连;设成 0.0.0.0 才能接受远程连接——但此时仍受账号 host 限制。很多人只改权限却忘了放开监听,或者开了 0.0.0.0 却没配防火墙,结果外网也能扫到端口。
- 修改
/etc/mysql/mysql.conf.d/mysqld.cnf中的bind-address = 0.0.0.0(内网场景下) - Linux上用
ufw allow from 192.168.5.0/24 to any port 3306限制流量入口 - 云服务器务必检查安全组,只放行指定内网段,别留
0.0.0.0/0
用localhost连接失败?这是Unix socket和TCP的区别
当应用用 localhost 当host连MySQL,默认走Unix socket文件(如 /var/run/mysqld/mysqld.sock),不走TCP/IP栈,也就绕过了 host 绑定逻辑。这时哪怕你建了 'user'@'127.0.0.1',也匹配不到 'user'@'localhost'(它们是两个独立账号)。
- 测试是否走TCP:把连接host改成
127.0.0.1而非localhost - 需要统一行为的话,删掉
'user'@'localhost',只保留'user'@'127.0.0.1'和具体内网IP - Docker或远程调试时尤其注意:宿主机用
127.0.0.1连容器MySQL,不是localhost
真正麻烦的从来不是怎么写那条GRANT语句,而是环境里已经存在的同名用户、代理层透传的IP、以及配置文件里被注释掉的旧bind-address——这些地方不逐个确认,光改权限没用。


















