为什么无法连接到 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"
相关推荐
ss27334 分钟前
AI时代首先数据库-PostgreSQL实战笔记 | 22 PostgreSQL实例与集群
数据库·笔记·postgresql
ss27334 分钟前
AI时代首先数据库-PostgreSQL实战笔记 | 21 PostgreSQL进程与内存架构介绍
数据库·笔记·postgresql
Henry-SAP2 小时前
SAP PP模块全景概览
数据库
喜欢吃豆2 小时前
Better Auth 深度解析:从用户认证到企业级身份基础设施
数据库·架构·权限·多租户
其实防守也摸鱼3 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
吹什么轩3 小时前
MySQL:数据库基础
数据库·mysql
内存漫游3 小时前
Undo、Redo 与事务回滚
数据库
FluxDB3 小时前
用 Rust + GPUI 重做数据库客户端
数据库·mysql
烬羽3 小时前
PostgreSQL:AI 时代原生的"隐型"向量数据库 — 用 pgvector 给消息表加上长期记忆
数据库·人工智能·程序员