资讯动态

PostgreSQL pg_hba.conf 配置实战:认证方式、IP限制与安全策略详解

发布时间:2026/10/16 4:10:14 来源:尧图企业网站定制
数据库搞到一半连不上连上来了密码报错密码对了又被地址拒掉好不容易调完规则发现又不生效——如果你也对pg_hba.conf有过这样的经历那这篇内容就是为你准备的。作为 PostgreSQL 访问控制的第一道闸门pg_hba.conf决定了谁能连、从哪个 IP 连、用什么方式认证以及最终能不能进库。很多人把它当成“出问题才想起来改两行的文件”改完还不 reload结果深夜里一个人在工位上看日志。这篇文章我从实战角度出发把pg_hba.conf的认证方式选型、IP 网段限制、安全策略和常见坑拆开讲清楚适合正在维护 PostgreSQL 实例的 DBA、后端开发也包括所有被“认证失败”折磨过的人。1. pg_hba.conf 到底在守护什么1.1 一次连接请求的“过闸机”过程PostgreSQL 的每个连接请求在真正执行 SQL 之前都要先过pg_hba.conf这一关。hba 是 host-based authentication 的缩写叫“基于主机的认证”但它管的远不止主机还管用户、数据库和认证方式。一个连接请求进来时服务端做的事情可以简单理解成四步拿到你的客户端地址、请求的数据库名、请求的用户名。从pg_hba.conf的第一行规则开始逐条向下匹配。遇到第一条同时满足类型、数据库、用户、地址的规则就停下来。按这条规则指定的认证方法执行认证或直接拒绝。关键在于“第一条匹配就生效”。这不是白名单联动后面再写多少条允许规则都没用。如果从头到尾没有任何一条规则能匹配当前请求那结果就是报FATAL: no pg_hba.conf entry for host ...。这个错误单词entry就是“没有匹配的条目”很多新手误以为是密码不对其实它更多时候是地址或用户没有被覆盖到。pg_hba.conf的每行规则有四个核心字段外加一个可选字段TYPE DATABASE USER ADDRESS METHODTYPE表示连接类型。常用取值包括local只匹配 Unix 套接字连接也就是本机通过 socket 连接。host匹配 TCP/IP 连接不管走没走 SSL。hostssl只匹配使用 SSL 加密的 TCP/IP 连接。hostnossl只匹配不使用 SSL 的 TCP/IP 连接。很多人写规则时只盯住后面的地址和认证方法忽略了TYPE结果本机psql连接走了local规则跟预期不一样半天找不出原因。理解了这一步排查问题的思路就清晰了一半。1.2 文件位置、加载时机和坑点pg_hba.conf默认放在数据目录下具体路径在不同的系统上差别很大。最常见的几个位置某发行版 PostgreSQL 15 默认/var/lib/pgsql/15/data/pg_hba.conf某发行版默认/etc/postgresql/15/main/pg_hba.conf自行编译安装时一般跟着--prefix走通常在data目录里。如果你记不住路径最稳妥的办法是直接进数据库查SHOW hba_file;这个命令会返回当前实例实际加载的pg_hba.conf完整路径。改文件之前先执行一下避免改了一个孤本配置半天不生效。修改pg_hba.conf不需要重启数据库只需要重新加载配置。常用的 reload 方式有三个systemctl reload postgresql pg_ctl reload -D /path/to/data或者在 psql 里直接执行SELECT pg_reload_conf();如果连 psql 都进不去那就只能到服务器上调用系统命令。这里有个很容易踩的坑很多人systemctl restart postgresql重启虽然也能加载但代价是连接全部中断主从切换场景下还可能引起不必要的故障转移。正确做法是能用 reload 就别 restart。reload 不会断掉现有连接只对新的连接请求生效这个特性在生产环境里非常重要。2. 认证方式怎么选从 trust 到 scram-sha-2562.1 常见认证方法速查与适用场景pg_hba.conf最后一列是认证方法这一列决定了客户端怎么证明“自己是自己”。PostgreSQL 支持的认证方法很多实际生产里常用的就那么几种。认证方法传输内容安全等级典型场景trust不认证低本机调试、单机临时环境reject直接拒绝-显式封禁某些来源password明文密码极低几乎不用应避免md5加盐 MD5 哈希低老版本兼容scram-sha-256挑战-响应不落明文高现代密码认证首选peer获取操作系统用户名高本机 socket 认证ident从 ident 协议取用户名中TCP 连接配合 pg_ident.conf 使用ldap走 LDAP 服务认证高企业统一账号体系cert客户端 SSL 证书高证书双向认证trust这个名字很迷惑它不是“信任”别人而是“我啥也不查你说是谁就是谁”。只要地址匹配任何人不需要密码就能以任意用户名连接数据库。开发环境图省事用了 trust过两天就发现数据被人删了这不是危言耸听。md5是很多老项目的默认选择但它在 PostgreSQL 里的实现方式比较弱。从 PostgreSQL 10 开始官方推荐scram-sha-256并在后续版本逐渐提高默认值。新项目坚决用scram-sha-256老项目也要及时升级。有些老客户端驱动不支持 SCRAM这时候才需要用md5先过渡但一定要有升级计划。2.2 密码认证配置详解设置与连接实测以最标准的scram-sha-256密码认证为例配置分两层第一层是 PostgreSQL 服务端密码加密方式第二层是pg_hba.conf里指定的认证方法。先看服务端参数SHOW password_encryption;正常应该返回scram-sha-256。如果不是可以修改postgresql.confpassword_encryption scram-sha-256注意这个参数只影响之后设置的密码已经存在的旧密码不会自动升级。所以最好是先改参数再给用户重新设置密码ALTER USER myuser WITH PASSWORD StrongPass123;然后在pg_hba.conf里把对应的连接规则写上# TYPE DATABASE USER ADDRESS METHOD local all all scram-sha-256 host all all 127.0.0.1/32 scram-sha-256 host all all 192.168.1.0/24 scram-sha-256配置完成后 reload。实际验证时我会用另一台机器或同一个机器指定 IP 去连psql -h 192.168.1.20 -p 5432 -U myuser -d mydb -W输入正确密码能进入输入错误密码会提示psql: error: FATAL: password authentication failed for user myuser这一步能证明规则匹配没有问题。生产环境里还可以通过log_line_prefix和log_connections参数观察认证过程不过初级排查时上面这几步已经够了。2.3 为什么不能随便用 trust我见过一个“案例”某团队在自己内网服务器上把pg_hba.conf写成了host all all 0.0.0.0/0 trust理由是“内网安全”。结果扫描一进来数据库直接被拖走。PostgreSQL 的默认安装是只监听 localhost 的但当你把listen_addresses改成*去支持远程连接时0.0.0.0/0 trust就相当于把数据库的钥匙挂在大门口。trust的真实应用场景只有一个正在初始化数据库、还没配置密码时临时进入本地维护。初始化完成后应该立刻把它改成scram-sha-256或peer。即使是在 Docker 容器里调试也尽量不要对网络地址使用trust最多对 Unix socket 临时用一下调试完马上改回来。3. IP 与网段限制把“门禁”精确到门牌号3.1 地址匹配规则与 CIDR 写法pg_hba.conf的ADDRESS字段支持 IPv4、IPv6 和 CIDR 子网写法。常见形式127.0.0.1/32只匹配本机 IPv4 回环地址。::1/128只匹配本机 IPv6 回环地址。192.168.1.0/24匹配192.168.1.0到192.168.1.255整个 C 段。0.0.0.0/0匹配所有 IPv4 地址。::0/0匹配所有 IPv6 地址。注意PostgreSQL 不是把192.168.1.0/24当成“从哪开始到哪结束”的区间来理解的而是严格按照 IP 与掩码做位运算。写错了子网掩码可能把不该放行的地址也放进来了。例如192.168.1.0/16实际覆盖的是192.168.0.0到192.168.255.255比你想象的整整大了 255 倍。还有一个容易忽略的点只有当 PostgreSQL 编译和运行支持 IPv6 时IPv6 地址才会被匹配。现代系统默认都支持但排查问题时如果 IPv6 规则一直不生效可以先查一下日志里的客户端地址是 IPv4-mapped 的::ffff:127.0.0.1还是原生 IPv6。3.2 默认配置逐条拆解新初始化的 PostgreSQL 实例pg_hba.conf通常长这样local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 local replication all peer host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256这里逐条解读第一条本机 Unix socket 连接所有库所有用户用peer认证即操作系统用户名必须和数据库用户名一致。第二条本机 IPv4 回环地址走scram-sha-256密码认证。第三条本机 IPv6 回环地址走scram-sha-256密码认证。后面的replication条目是给流复制专用连接用的只有本机地址能连。这套默认配置的思路很清晰本机用系统身份或密码验证网络地址一概不开放。真正的生产环境通常会改掉peer因为用运维脚本或服务进程连库时系统用户和数据库用户经常对不上。但改之前要明白peer本身是很安全的认证它建立在“本机操作系统账号可信”的前提上问题只是它不适合所有自动化场景。3.3 典型局域网/多环境隔离配置示例假设一台 PostgreSQL 服务器上有多个数据库要分给不同小组使用。可以用这样一组规则实现隔离# TYPE DATABASE USER ADDRESS METHOD local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 # 开发人员 host devdb devuser 10.10.20.0/24 scram-sha-256 # 生产应用服务器 host proddb produser 10.10.10.0/24 scram-sha-256 # 拒绝其他所有网络连接 host all all 0.0.0.0/0 reject host all all ::0/0 reject这组配置中最后两条reject相当于显式声明“除了上面允许的其他统统不要”。虽然 PostgreSQL 默认就是“无匹配则拒绝”但显式写出来有两个好处改配置的人能一眼看懂边界。如果上面某个规则写错导致漏放行日志里不会出现“没有匹配条目”的误导性报错而会直接表现为连接被拒信息更明确。不过要特别注意顺序reject规则必须放在所有允许规则的后面。如果把它放到最前面那它会成为第一条匹配后面所有允许规则都成了摆设。这种“一把锁锁死全楼”的失误我在故障排查看过不止一次。4. 安全策略进阶规则顺序、最小权限与防御思路4.1 规则从上到下匹配一个顺序引发的故障前面强调过“第一条匹配生效”这里用实际例子加深印象。假设你的服务器对外只允许192.168.80.55这个开发机连接于是你写了一条规则# (错误示例) host all all 0.0.0.0/0 reject host all all 192.168.80.55/32 scram-sha-256结果开发机死活连不上因为第一条0.0.0.0/0 reject已经把192.168.80.55也拒了。系统不会“跳过拒绝规则再看后面的允许规则”而是直接选择一个能覆盖到请求的最早规则执行。正确顺序是先允许特定 IP再拒绝剩余来源。# (正确示例) host all all 192.168.80.55/32 scram-sha-256 host all all 0.0.0.0/0 reject这一类问题还有变体一个网段里大部分人要放行单个别 IP 要封禁。先写封禁规则再写网段允许规则这样被封禁的 IP 会在第一条匹配掉以后面的规则为准的情况不会出现。原则就是“把最具体的规则放最前面”。跟防火墙规则一个逻辑先细化后兜底。4.2 最小权限数据库、用户、地址都别贪大安全策略里最实用的理念是“最小权限”。到了pg_hba.conf这里就是把三个维度都尽量收紧。数据库维度能用具体库名就不用all。比如备份脚本只需要连mydb那就只给它开mydb的规则不要顺手写成all。这样即使这个账号被破解攻击者也只是拿到一个库的入口而不是所有库。用户维度避免使用超管postgres作为业务连接账号。数据库创建独立业务角色只授权需要的权限然后用业务角色连库。pg_hba.conf里尽量写业务角色名。有人觉得多建几个角色麻烦但安全本身就是用“麻烦”换“可控”。地址维度能用具体 IP 或小网段就不用/0。就算被迫对公网开放也要用云防火墙或安全组先把端口限制住然后pg_hba.conf只放行真正需要访问的来源。多一层限制永远比少一层强。另外还有一个经常被忽略的replication。流复制用户通常有复制特权这种连接能读取到和写入 WAL 日志相关的重要数据。默认配置已经限制了 replication 只能从 localhost 连接生产环境如果主从不在同一台机器需要放开某个内网 IP务必将网段写到最小单位。千万不要图省事写# (危险示例) host replication all 0.0.0.0/0 scram-sha-256这意味着任何能猜出密码的机器都能以流复制身份连进来。流复制特权远不止“复制数据”一些场景下甚至可以拿到全库数据甚至执行危险操作。对它的访问控制建议和超级用户同等对待。4.3 强制 SSL从“能用”到“必须加密”密码认证解决的是“你是谁”的问题SSL 解决的是“通信过程不被偷听”的问题。scram-sha-256已经能保证密码不以明文流动但认证成功之后普通 SQL 查询和数据传输还是明文的在公网甚至共享内网上都容易被截获。所以生产环境里建议开启 SSL并让pg_hba.conf只接受 SSL 连接。在postgresql.conf里配置ssl on ssl_cert_file server.crt ssl_key_file server.key然后pg_hba.conf里把对外连接的TYPE从host改成hostssl# TYPE DATABASE USER ADDRESS METHOD hostssl all all 192.168.10.0/24 scram-sha-256 hostnossl all all 0.0.0.0/0 reject这里的hostnossl是一个防御性兜底确保任何非 SSL 连接都被明示拒绝。如果只写了hostssl没写hostnossl那么非 SSL 连接会因为“找不到匹配规则”被默认拒绝效果也是一样的。显式写出来的好处同样是方便将来读配置的人理解意图且日志更明确。配置完 SSL 后用psql连一次观察连接信息SELECT ssl, version, cipher FROM pg_stat_ssl;如果ssl列为t说明这条连接确实走了加密。还可以在客户端连接时强制要求psql host192.168.10.8 dbnamemydb usermyuser sslmoderequire4.4 配置后的验证与回滚技巧每次改完pg_hba.conf建议做三件事第一用pg_hba_file_rules视图检查配置是否被正确解析SELECT line_number, type, database, user_name, address, netmask, auth_method, error FROM pg_hba_file_rules;这个视图非常实用。如果配置文件里有语法错误它会在error列显示出来而且不会影响旧的已加载配置。也就是说加载失败时数据库仍然沿用旧规则在跑不会因为新文件写错就完全锁死。第二保存一份带日期的备份再 reload。pg_hba.conf文件很小但改坏一个字符可能造成大面积连接失败。备份命令很简单cp pg_hba.conf pg_hba.conf.bak.$(date %F_%H-%M)第三reload 后用真实客户端做一次“最小连通测试”。不要只在数据库本机psql测因为本机可能走local规则你真正改的却是host规则。要用远程机器或显式指定-h IP来验证。测试时加上-w会强制不提示输入密码但那样可能掩盖密码交互所以更合适的做法是psql -h 192.168.10.8 -p 5432 -U myuser -d mydb -W确认输出没有错误后再做下一个改动。一次只改一个点不要同一时间改三行规则又改 SSL否则出问题后很难定位是哪一步破坏了连接。5. 常见问题排查与配置失误实录5.1 “no pg_hba.conf entry”的真相与定位看到FATAL: no pg_hba.conf entry for host 192.168.10.8, user postgres, database mydb, no encryption时首先要纠正认知这不是“没有配置文件”而是“没有一条规则能匹配这个连接”。导致这个问题的原因通常有三个地址没覆盖。比如只写了192.168.10.0/24但客户端实际是192.168.11.8。用户或数据库名没匹配上。规则里写了具体用户客户端用了别的用户。类型不匹配。客户端用的是 SSL但规则只写了hostnossl或者客户端没用 SSL规则只写了hostssl。定位方式可以通过开启连接日志log_connections on log_disconnections on然后重新触发一次连接去看日志中记录的客户端 IP、端口和协议。如果日志显示connection received: host::1 port...而你的配置只写了 IPv4 的127.0.0.1/32那也会出现“明明本机为什么连不上”的情况。原因是被解析成了 IPv6 回环地址你却没写 IPv6 规则。处理很简单补上::1/128规则即可。5.2 密码认证失败的七个常见原因password authentication failed是出现频率最高的报错。它不一定代表密码真的错了我整理几个容易被忽略的原因原因说明密码确实不对角色密码被改过或新建角色没设密码pg_hba 方法不对规则写了md5但角色密码是scram-sha-256存储角色不存在报错可能被包装成密码认证失败密码过期开启了valid until限制客户端驱动太老老驱动不支持 SCRAM只能走 md5特殊字符被客户端转义密码含、%、空格连接串没处理规则顺序被截胡更前面的规则匹配到了但认证方法不适用于当前用户最常见的其实是第一种和第三种。排查时先确认角色是否存在SELECT rolname, rolvaliduntil FROM pg_authid WHERE rolname myuser;然后确认角色密码加密方式SELECT rolname, rolpassword IS NOT NULL AS has_password FROM pg_authid WHERE rolname myuser;注意密码字段本身不要直接输出那是哈希值没法反推出明文。如果确定密码没问题再看pg_hba_conf里使用的认证方法是否和密码存储类型一致。最简单的方法是把规则统一改成scram-sha-256并确保postgresql.conf里password_encryption也是scram-sha-256然后重新设置一次密码。5.3 reload 与 restart 到底什么时候用很多配置管理员习惯一改配置就systemctl restart postgresql这在单机环境只是代价高一点在主从环境可能就是一次灾难。reload 是平滑重读配置已经建立的长连接不受影响新连接按新规则处理。restart 会杀掉所有后端进程如果正好有长事务在跑可能导致主从切换或数据恢复流程。pg_hba.conf的修改只需要 reload。判断 reload 是否生效可以执行SELECT pg_reload_conf();或检查pg_hba_file_rules视图它反映的是最新一次成功加载的结果。如果error列为空说明配置已经生效且被解析成功。有一个细节需要特别提醒如果pg_hba.conf的权限不对reload 后系统可能拒绝读取。配置文件最好保持数据目录所有者为数据库系统用户文件权限设置为600或640不要用777。这不是洁癖PostgreSQL 对权限异常会直接给出could not open configuration file的日志。5.4 一条“看似正确”的规则为什么会失效有次我帮一个同事排查他的pg_hba.conf里明明写了host mydb myuser 0.0.0.0/0 scram-sha-256但远程连接还是被拒。最后发现问题出在他的postgresql.conf里listen_addresses localhost服务端根本没有监听外部网卡pg_hba.conf写得再花哨也没用。连接层的第一道门槛其实是listen_addresses它决定 PostgreSQL 进程绑定到哪个地址。只有监听到了外部 IPhost规则才有意义。排查顺序应该是检查端口是否监听ss -lnpt | grep 5432检查监听地址SHOW listen_addresses;检查pg_hba.conf规则检查防火墙和安全组这四个层面缺一不可。很多“pg_hba.conf没用”的传闻最后其实都是监听地址或防火墙的问题。6. 我自己在用的基线配置模板文章最后分享一套我实际部署小规模 PostgreSQL 时使用的模板不含花哨内容适合大多数中低风险业务。先看整体# PostgreSQL pg_hba.conf 基线模板 # 原则本机 socket 用 peer内网密码认证公网只开 SSL末尾拒绝一切。 local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 # 内部管理网段DBA 和运维跳板机 hostssl all all 10.0.0.0/8 scram-sha-256 # 应用服务器网段按实际子网替换 hostssl myappdb appuser 172.16.10.0/24 scram-sha-256 # 备份服务器专用地址 hostssl myappdb backupuser 172.16.20.5/32 scram-sha-256 # 流复制仅允许主从内网互通按实际 IP 替换 hostssl replication replicator 172.16.30.10/32 scram-sha-256 hostssl replication replicator 172.16.30.20/32 scram-sha-256 # 拒绝对外网的非 SSL 连接 hostnossl all all 0.0.0.0/0 reject hostnossl all all ::0/0 reject这套模板有几个特点值得说明。第一几乎都用hostssl保证业务连接必须走加密。内部网段我也坚持用 SSL因为内网不等于没问题很多安全事故就是从内网横向移动开始的。第二业务账号不用all用户。应用只访问myappdb就用appuser单独建角色连接包带上这个用户规则只给它开一条。攻击面越小恢复越容易。第三备份和流复制单独列地址。备份机是高权限用户不能跟普通应用混在同一个网段规则里流复制用户单独用固定 IP 放行不用0.0.0.0/0。第四最后加了两条reject兜底。即使上面某个网段写错也能保证非 SSL 连接直接拒掉不会偷偷用自己的密码方法进行。使用这个模板时需要根据实际情况改掉数据库名、用户名、网段和复制地址。改完后执行 reload然后按前面说的验证流程测一遍。如果项目要求更细的权限可以把业务账号再拆分成读写账号和只读账号分别写到不同的规则行里。多记一个账号的麻烦远小于数据泄露后写事故报告的痛苦。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑