新安装的 PostgreSQL 服务器默认只接受来自本机的连接。如果要连接到远程服务器,需要配置以下内容:
- 配置 PostgreSQL 监听远程连接。
- 添加一条
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"