花拾录
← 返回知识库

新加的 PostgreSQL 放行规则不生效:pg_hba 是首个匹配生效

数据库导入2026/09/220 阅读0 评论

你为了允许一个新网段连数据库,在认证配置里加了一条放行规则。保存、reload、测试——还是被拒。规则明明写了,为什么不生效?

现象

新加的一条认证放行规则不起作用,从某些地址连接数据库仍然被拒绝。反复检查规则本身的写法(类型、库名、用户名、地址、认证方式)都正确,但就是不生效。

诡异的是:把这条规则挪到文件里别的位置,有时候突然就好了——于是更加困惑,因为"内容没变,只是位置变了"。

根因

pg_hba.conf 的匹配规则是首个匹配生效(first match wins),不是"任意一条匹配就放行"。

它的工作方式是:PostgreSQL 从文件第一行开始往下扫,找到第一条"来源地址、数据库、用户"都匹配当前连接的规则,就用这条规则指定的认证方式处理,然后停止扫描——后面的规则完全不看。

这就意味着:规则的位置就是语义。 如果你新加的规则写在了一条更宽的规则后面,而那条宽规则恰好也匹配你的连接,那么你的新规则永远不会被执行到。

典型的翻车场景是:把具体规则加在文件末尾,而文件里早有一行宽泛的规则:

# 早就在这里的宽规则
host    all    all    192.168.0.0/16    trust
# 你新加的(永远不会被执行到)
host    mydb   appuser  192.168.0.50/32  scram-sha-256

你的连接来自 192.168.0.50,它同时匹配上面两条,但第一条先被扫到,所以就走 trust 了——而如果你的意图是"这个用户必须用密码",那就没实现。

解决

第一步,找出文件里所有能匹配你那条连接的宽规则。

用地址掩码范围去判断——比如你的连接来自 192.168.0.50,那么 192.168.0.0/24、192.168.0.0/16、0.0.0.0/0 都会匹配它。

第二步,把你新加的具体规则移到这些宽规则的前面**:**

# 具体规则在前
host    mydb    appuser   192.168.0.50/32   scram-sha-256
host    mydb    appuser   192.168.0.0/24    scram-sha-256
# 宽规则在后
host    all     all       0.0.0.0/0         reject

顺序原则是:从具体到宽泛,从特殊到一般。

第三步,reload 生效:

select pg_reload_conf();

第四步,验证正向和负向两种情况——目标地址能连上、其他地址仍被拒。

排错小技巧:如果实在搞不清是哪条规则在生效,可以临时在规则上加一个不存在的认证方式,让 PostgreSQL 报错并提示它用的是哪一行。

延伸与预防

把这句口诀记住:这个配置文件是顺序敏感的,位置就是语义。

维护的时候,建议在文件里做分区注释:

# === 具体规则(单 IP / 单库 / 单用户)===
# === 中等范围规则(内网网段)===
# === 兜底规则(reject all)===

每次加新规则,先想清楚它应该插在哪个分区,而不是习惯性追加到末尾。

同样的"首个匹配生效"语义也出现在很多其他配置系统里:

  • iptables / 防火墙规则:从上到下匹配,一条 ACCEPT 或 DROP 会终止后续判断;
  • 路由表:最长前缀匹配,但同长度时按优先级/顺序;
  • nginx 的 location 匹配:有前缀、正则、精确匹配的优先级规则;
  • Apache 的 <Directory> / <Location>:也是先匹配先生效。

遇到"配置写了不生效",顺序是第一批要怀疑的地方。这个模式值得单独记一笔。

评论(0)

  • 还没有评论,来抢沙发~

相关文章