MySQL用户IP限制需创建特定host账号(如'user'@'192.168.1.100'),而非在'%''账号上补救;localhost与127.0.0.1视为不同账号;Host不支持CIDR,仅支持'%'、'_'和字面量;修改后需FLUSH PRIVILEGES并重启应用验证。

MySQL 用户账号绑定 IP 地址的正确写法
MySQL 的用户权限是「用户名 + 主机名」联合唯一识别的,不是只看用户名。想限制某个用户只能从特定 IP 登录,本质是创建或修改一个 user@'192.168.1.100' 这样的账号,而不是给 user@'%' 加个“白名单开关”。
常见错误是执行 GRANT ... ON *.* TO 'user'@'%' 后再试图用配置文件或防火墙“补救”,结果权限没生效、连接仍被允许——因为 'user'@'%' 本身就允许任意 IP 连接,优先级高于更具体的 'user'@'192.168.1.100'(MySQL 按主机名匹配最长前缀规则排序)。
- 先查清当前有哪些同名用户:
SELECT User, Host FROM mysql.user WHERE User = 'your_user'; - 删掉通配符账号(如果不需要):
DROP USER 'your_user'@'%'; - 只保留带具体 IP 或子网的账号:
CREATE USER 'your_user'@'192.168.1.100' IDENTIFIED BY 'strong_pass'; - 授权时也必须用完全匹配的账号:
GRANT SELECT ON mydb.* TO 'your_user'@'192.168.1.100';
localhost 和 127.0.0.1 在 MySQL 权限中不是一回事
MySQL 把 'user'@'localhost' 和 'user'@'127.0.0.1' 当作两个独立账号。前者走 Unix socket(默认),后者走 TCP/IP。很多本地脚本连不上,就是因为只建了 localhost 账号,但程序里写的是 127.0.0.1 作为 host 参数。
如果你的应用明确指定 host=127.0.0.1(比如某些 ORM、Docker 容器内连接),那 'user'@'localhost' 的权限完全不生效。
- 检查连接方式:
mysql -h 127.0.0.1 -u your_user -p→ 匹配'user'@'127.0.0.1' -
mysql -h localhost -u your_user -p→ 匹配'user'@'localhost'(注意:不是 DNS 解析后的 IP) - 若需两者都支持,得分别建两个账号并单独授权,不能偷懒只建一个
子网掩码和通配符 Host 的安全边界
MySQL 不支持 CIDR 表示法(如 '192.168.1.0/24'),只认 '%'、'_' 和字面量。想限制一个 C 段,得写成 '192.168.1.%';想限制单个 IPv6 地址,必须写全(如 '2001:db8::1'),不支持 '2001:db8::%' 这类简写。
容易踩的坑是误以为 '192.168.%' 只匹配 C 段,其实它还会匹配 192.168.100.200、192.168abc.example.com —— 因为 % 是 SQL 模式通配符,不做 IP 校验。
- 生产环境慎用
%,尤其不要给管理员账号用 - IPv6 地址必须用方括号包裹:授权时写
'user'@'2001:db8::1',但连接字符串里仍是host=2001:db8::1 - 若需精细控制,建议在数据库前端加代理(如 ProxySQL)或依赖操作系统防火墙(iptables/nftables)做第一层过滤
修改权限后必须刷新,且客户端可能缓存失败凭据
执行 CREATE USER 或 GRANT 后,权限变更不会自动生效到已存在的连接,但新连接会读取最新权限表。不过有个关键点常被忽略:MySQL 服务端不主动通知客户端“你的旧连接已失效”,所以旧连接仍能继续操作,直到断开重连。
更隐蔽的问题是客户端(尤其是 PHP 的 mysqli/pdo、Python 的 PyMySQL)在连接失败时可能缓存了错误认证状态,换 IP 后反复报 Access denied for user,实际是因为没删旧账号,或者客户端复用了连接池里的失效句柄。
- 改完权限后运行:
FLUSH PRIVILEGES;(虽然多数情况非必需,但可排除权限表加载异常) - 确认无其他同名账号干扰:
SELECT User, Host, authentication_string FROM mysql.user WHERE User = 'your_user'; - 客户端侧强制关闭连接池、重启应用,避免复用旧连接
- 用
mysql -h 实际IP -u your_user -p手动验证,别只信应用日志
IP 限制这事,核心不在语法多难,而在于你是否清楚自己到底在哪个账号上操作、客户端走的是哪条网络路径、以及权限表有没有被多个相似 Host 条目悄悄覆盖。漏掉其中一环,就等于没设防。


















