为什么无法连接到 PostgreSQL?

新安装的 PostgreSQL 服务器默认只接受来自本机的连接。如果要连接到远程服务器,需要配置以下内容:

  1. 配置 PostgreSQL 监听远程连接。
  2. 添加一条 pg_hba.conf 规则,允许远程客户端通过身份验证。

配置 PostgreSQL 监听远程连接

本例中,PostgreSQL 服务器名为 pg-server.example.test,文档示例 IP 地址为 203.0.113.10。远程客户端的文档示例 IP 地址为 203.0.113.25。

如果尚未配置监听地址,远程客户端尝试连接时会收到连接被拒绝的错误:

text 复制代码
$ psql -h pg-server.example.test -p 5432 -U postgres -d postgres
psql: error: connection to server at "pg-server.example.test" (203.0.113.10), port 5432 failed: Connection refused
	Is the server running on that host and accepting TCP/IP connections?

PostgreSQL 默认只监听 loopback 地址。可以在服务器上查看当前监听地址:

text 复制代码
# ss -ltnp | grep 5432
LISTEN 0      200        127.0.0.1:5432       0.0.0.0:*    users:(("postgres",pid=2039980,fd=8))
LISTEN 0      200            [::1]:5432          [::]:*    users:(("postgres",pid=2039980,fd=7))

每行的第一个地址是本地监听地址。127.0.0.1 和 ::1 都是 loopback 地址,因此远程客户端无法访问它们。

服务器的 postmaster.pid 文件也会记录监听地址:

text 复制代码
# cat /u01/pg/postmaster.pid
2350229
/u01/pg
1791443245
5432
/run/postgresql
localhost
131    163886
ready

其中的 localhost 表明 PostgreSQL 启动时只监听了本机地址。

这是由 postgresql.conf 中的以下设置造成的:

text 复制代码
# grep listen /u01/pg/postgresql.conf
#listen_addresses = 'localhost'         # what IP address(es) to listen on;

该设置被注释掉了,因此 PostgreSQL 默认使用 localhost。取消注释后,如果只希望 PostgreSQL 监听服务器的 LAN 地址,就将其设为该地址;如果希望监听本机所有网络接口,则设为 *:

conf 复制代码
listen_addresses = '*'

listen_addresses 只在服务器启动时生效,因此修改后必须重启 PostgreSQL。仅重新加载配置并不足够:

text 复制代码
# systemctl restart postgresql-18.service

重启后,检查监听地址:

text 复制代码
# ss -ltnp | grep 5432
LISTEN 0      200          0.0.0.0:5432       0.0.0.0:*    users:(("postgres",pid=2350229,fd=7))
LISTEN 0      200             [::]:5432          [::]:*    users:(("postgres",pid=2350229,fd=8))

输出表明 PostgreSQL 正在监听本机所有 IPv4 和 IPv6 网络接口。

postmaster.pid 文件也显示服务器是以 listen_addresses = '*' 启动的:

text 复制代码
# sed -n '1,8p' /u01/pg/postmaster.pid
2350229
/u01/pg
1791443245
5432
/run/postgresql
*
131    163886
ready

服务器日志确认 PostgreSQL 正在监听所有 IPv4 和 IPv6 地址:

text 复制代码
2026-10-08 07:07:25.950 GMT [2350229] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2026-10-08 07:07:25.950 GMT [2350229] LOG:  listening on IPv6 address "::", port 5432

现在远程客户端可以访问服务器 203.0.113.10:5432。但再次连接时会遇到 HBA 错误,这表示网络监听已经正常工作,但客户端尚未获得访问授权:

text 复制代码
$ psql -h pg-server.example.test -p 5432 -U postgres -d postgres
psql: error: connection to server at "pg-server.example.test" (203.0.113.10), port 5432 failed: FATAL:  no pg_hba.conf entry for host "203.0.113.25", user "postgres", database "postgres", no encryption

配置远程客户端的基于主机的身份验证

HBA 是 host-based authentication (基于主机的身份验证)的缩写。pg_hba.conf 文件控制谁可以连接、从哪里连接、连接哪个数据库、使用哪个 PostgreSQL 角色,以及该角色必须如何进行身份验证。

对于此 PostgreSQL 18 安装,可以用以下命令查看当前生效的规则:

text 复制代码
# grep -vE '^[[:space:]]*(#|$)' /u01/pg/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 套接字连接使用 peer 身份验证,本地 TCP 连接使用 scram-sha-256 身份验证。其中没有一条允许远程客户端 203.0.113.25 连接。

如果你和我一样懒,可以用下面三条规则,让任意 IPv4 或 IPv6 客户端,以及本地 Unix 套接字连接,都无需密码就能连上:

conf 复制代码
host    all    all    0.0.0.0/0    trust
host    all    all    ::/0         trust
local   all    all                 trust

这办法方便得不得了,危险得也离谱:任何能够访问服务器的人,都可以不输密码,以任意角色连接任意数据库。这些规则只能用于你自己的测试环境,千万别放到生产环境。生产环境可以使用更安全的规则,例如:

conf 复制代码
host    postgres    postgres    203.0.113.25/32    scram-sha-256

各字段的含义如下:

  • host:适用于 TCP/IP 连接。
  • 第一个 postgres:数据库名。
  • 第二个 postgres:PostgreSQL 角色名。
  • 203.0.113.25/32:只允许这个 IPv4 客户端地址。也可以改用较大的 203.0.113.0/16 网段,允许该网段中的客户端连接。
  • scram-sha-256:要求使用 SCRAM 密码身份验证。

保存文件后,重新加载 HBA 配置。pg_hba.conf 只需重新加载即可生效,无需完整重启:

text 复制代码
# systemctl reload postgresql-18.service

如果尚未为该角色设置密码,请设置一个:

text 复制代码
# sudo -u postgres psql -c "ALTER ROLE postgres WITH PASSWORD 'yuanyao';"

现在客户端可以连接,并在提示时输入密码:

text 复制代码
$ psql -h pg-server.example.test -p 5432 -U postgres -d postgres
Password for user postgres:
psql (18.6)
Type "help" for help.

# \conninfo
        Connection Information
      Parameter       |     Value
----------------------+----------------
 Database             | postgres
 Client User          | postgres
 Host                 | pg-server.example.test
 Host Address         | 203.0.113.10
 Server Port          | 5432
 Options              |
 Protocol Version     | 3.0
 Password Used        | true
 GSSAPI Authenticated | false
 Backend PID          | 9790
 SSL Connection       | false
 Superuser            | on
 Hot Standby          | off
(13 rows)

如果只是临时测试,也可以通过 PGPASSWORD 提供密码:

text 复制代码
$ PGPASSWORD='yuanyao' psql -h pg-server.example.test -p 5432 -U postgres -d postgres

也可以把密码写入连接 URI,不过将密码保存在 shell 历史记录或命令行中可能会导致密码泄露:

text 复制代码
$ psql "postgresql://postgres:yuanyao@pg-server.example.test:5432/postgres"
相关推荐
这个DBA有点耶8 小时前
从反向扫描O(n)到正向扫描O(1):降序索引的物理机制与混合排序匹配规则
数据库
2501_933923259 小时前
解读Redis:单线程模型
数据库·redis·缓存
Tapdata11 小时前
被忽略的第三类上下文:Agent 进入真实业务后,还缺什么?
数据库·人工智能·架构
小科先生12 小时前
Java springboot调用数据库的基本流程
java·数据库·spring boot
星恒随风12 小时前
MySQL 从零入门(四):表的增删改查与基础查询详解
linux·服务器·数据库·笔记·mysql
Pniubi14 小时前
MySQL靠什么实现事务的?事务隔离级别有哪些?
java·数据库·mysql
数据库小学妹14 小时前
pgbouncer 事务池:prepared statement、临时表与会话状态
数据库·后端·postgresql
Lucifer三思而后行15 小时前
最近折腾了一下金仓数据库的备份恢复
数据库·备份恢复
草莓熊Lotso16 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
进击的荆棘17 小时前
MySQL——库的操作
数据库·mysql