MySQL 创建用户时如何指定允许连接的 IP 或主机名
MySQL 用户名由
'user'@'host'两部分组成,其中
host部分直接决定该用户能从哪些客户端发起连接。它不是“额外配置项”,而是创建用户时必须显式声明的核心组成部分。
常见误区是先用
CREATE USER 'u1'@'localhost'创建,再试图用
GRANT ... ON *.* TO 'u1'改权限——这不会改变
host值,只会报错或静默失败。
'localhost':仅允许本机 Unix socket 或 127.0.0.1(取决于 MySQL 配置),不等价于
'127.0.0.1'(后者走 TCP)
'192.168.1.100':只允许来自该 IP 的 TCP 连接
'192.168.1.%':匹配 192.168.1 网段所有 IPv4 地址(注意:不匹配 IPv6)
'%.example.com':匹配所有以
.example.com结尾的主机名(需 DNS 可解析)
'%':允许任意主机连接(含公网),生产环境应避免
使用 CREATE USER 时必须写全 host 部分
不能省略
@'host',也不能只写用户名。MySQL 5.7+ 默认不允许空 host,且
CREATE USER 'u1'会被解释为
'u1'@'%',这是高危行为。
正确写法示例:
CREATE USER 'app_user'@'10.20.30.40' IDENTIFIED BY 's3cur3_p@ss';
如果想允许多个固定 IP,需分别创建多个用户(MySQL 不支持单用户绑定多个 host):
CREATE USER 'app_user'@'10.20.30.40' IDENTIFIED BY 's3cur3_p@ss'; CREATE USER 'app_user'@'10.20.30.41' IDENTIFIED BY 's3cur3_p@ss';
注意:
IDENTIFIED BY在 MySQL 8.0+ 中仍有效,但推荐用
IDENTIFIED WITH caching_sha2_password BY '...'显式指定认证插件。
GRANT 语句中的 host 必须与 CREATE USER 一致
GRANT不会修改用户定义的 host,它只是给某个已存在的
'user'@'host'授权。若执行:
CREATE USER 'api'@'192.168.5.0/24'; GRANT SELECT ON mydb.* TO 'api'@'%';
第二行会报错:
ERROR 1396 (HY000): Operation GRANT failed for 'api'@'%',因为用户实际是
'api'@'192.168.5.0/24'(MySQL 8.0+ 支持 CIDR 写法,但仍是完整 host 字符串)。
正确做法是:
CREATE USER 'api'@'192.168.5.0/24' IDENTIFIED BY 'p@ss'; GRANT SELECT ON mydb.* TO 'api'@'192.168.5.0/24';
另外,
host匹配是**精确字符串匹配**,不支持通配符嵌套(如
'192.168.*.100'无效)。
验证用户 host 是否生效及常见连不上原因
连不上最常被忽略的是:MySQL 服务是否监听了对应网卡、防火墙是否放行 3306 端口、客户端是否用了正确的 host 参数(例如用
mysql -h 127.0.0.1 -u u1和
mysql -h localhost -u u1可能命中不同用户)。
检查当前所有用户及其 host:
SELECT User, Host FROM mysql.user;
查看某用户具体权限(确认 host 完全一致):
SHOW GRANTS FOR 'webapp'@'172.16.0.5';
特别注意:MySQL 8.0+ 默认启用
skip_name_resolve = ON,此时 host 部分不会做 DNS 反查,
'user'@'host.example.com'只匹配客户端 TCP 连接时声明的 hostname(通常不可靠),建议一律用 IP 或
'%'+ 网络层控制。
host 字符串一旦写错(比如多一个空格、大小写不一致、用了中文引号),用户就无法匹配,且错误提示往往模糊(如
Access denied for user),排查时务必逐字符核对
User和
Host输出结果。
