grant语句中不存在hash字段,正确参数是host(全大写),用于指定用户连接来源;写错为hash或小写host会导致语法错误;host值如'192.168.1.%'仅作字符串前缀匹配,不支持cidr。

GRANT语句里的HASH不是IP,是HASH字段写错会直接拒绝授权
MySQL的GRANT语句中根本没有HASH字段——这是常见笔误。真正起作用的是HOST参数(注意全大写、无下划线),它定义账户可连接的来源主机。写成HASH或host小写会导致语法错误:ERROR 1064 (42000): You have an error in your SQL syntax。
正确写法必须严格使用HASH字段名?不,是HASH根本不存在;必须用HOST,且它出现在username@'HOST'这个位置:
GRANT SELECT ON mydb.* TO 'appuser'@'192.168.1.100';
-
'192.168.1.100'是精确IP,只允许该地址连接 -
'192.168.1.%'匹配C类网段(注意%不能出现在IP中间) -
'%.example.com'匹配域名后缀,不适用于IP限制场景 - 空字符串
''或'%'表示任意主机——这是默认值,也是最危险的配置
localhost和127.0.0.1在MySQL里不是一回事
MySQL把'localhost'视为特殊标识,强制走Unix socket连接,完全绕过TCP/IP栈;而'127.0.0.1'走TCP,受HASH(应为HOST)规则约束。想让本地应用也受IP限制,就不能用'localhost',得显式指定'127.0.0.1':
GRANT ALL PRIVILEGES ON *.* TO 'devuser'@'127.0.0.1' IDENTIFIED BY 'pwd123';
- 如果同时存在
'devuser'@'localhost'和'devuser'@'127.0.0.1',MySQL优先匹配更具体的host(按字符长度排序,'localhost'比'127.0.0.1'短,但规则更特殊) -
FLUSH PRIVILEGES不是每次都要执行:只有修改mysql.user表直改才需要;用GRANT语句操作会自动刷新权限缓存 - 客户端连接时必须显式指定
-h 127.0.0.1,否则mysql命令行默认用localhost,连不上@'127.0.0.1'账户
IP通配符%和_的行为和防火墙规则完全不同
MySQL的HASH(再次强调:是HOST)通配符仅支持%(任意长度)和_(单字符),且只作用于DNS解析后的结果或原始IP字符串——它不做子网掩码计算,也不查路由表:
GRANT SELECT ON sales.* TO 'report'@'10.0.5._'; -- 错!_不能匹配数字段,只会字面匹配下划线字符
-
'10.0.5.%'合法,匹配10.0.5.1、10.0.5.255、10.0.5.100:33061(端口不影响匹配) -
'10.0.5.0/24'非法,MySQL不识别CIDR格式 - 若应用通过NAT或代理访问,
HASH看到的是代理IP,不是真实客户端IP——这时靠MySQL自身无法做真实IP限制,得前置加Web服务器或防火墙 - IPv6地址必须用方括号包裹:
'2001:db8::1'要写成'2001:db8::1',但MySQL 5.7+支持,旧版本可能截断
SHOW GRANTS看不到完整HOST值,得查mysql.user表
SHOW GRANTS FOR 'user'@'host'输出里的host可能被截断或显示为%,尤其当实际值含通配符时。最可靠的方式是直接查系统表:
SELECT User, Host FROM mysql.user WHERE User = 'appuser';
- 返回结果中
Host列内容才是MySQL实际匹配依据,比如显示192.168.1.%就说明没写错 - 删除错误账户用
DROP USER 'appuser'@'wrong-host';,不能只删User名 - 修改现有账户HOST需先
DROP USER再GRANT重建——MySQL不支持ALTER USER ... RENAME HOST - 账户名和HOST区分大小写:'
AppUser@'192.168.1.100' ≠ 'appuser@'192.168.1.100'
HOST字段的值一旦设定,就锁死了连接入口,但它的匹配逻辑既不等价于iptables,也不等价于应用层白名单——它只在TCP握手完成、认证阶段生效,且完全依赖客户端声明的源IP(可被伪造,所以生产环境务必配合网络层防护)。











