postgresql默认拒绝远程连接,须修改postgresql.conf的listen_addresses参数(如设为'127.0.0.1,192.168.1.100')和pg_hba.conf添加对应cidr规则(如host all all 192.168.1.0/24 md5),再reload或重启服务生效。

PostgreSQL 默认拒绝所有远程连接,必须显式修改两个配置文件并重启服务才能生效;但直接放开 0.0.0.0/0 和 listen_addresses = '*' 是高危操作,生产环境应严格限制 IP 范围与用户权限。
修改 postgresql.conf 启用 TCP/IP 监听
PostgreSQL 不监听远程请求的根本原因是 listen_addresses 默认只设为 'localhost'。这个参数控制数据库接受连接的网络接口,不是防火墙或端口开关。
- 找到
postgresql.conf(常见路径:/etc/postgresql/*/main/postgresql.conf或/var/lib/pgsql/*/data/postgresql.conf) - 取消注释并修改该行:
listen_addresses = 'localhost'→listen_addresses = '127.0.0.1,192.168.1.100'(推荐指定内网 IP,而非'*') - 若需支持 IPv6,额外加上
::1;不要写成'*'除非你清楚后果 - 修改后不重启服务,
pg_ctl reload或systemctl reload postgresql即可生效(但部分旧版本仍需重启)
在 pg_hba.conf 中添加精确的访问规则
pg_hba.conf 决定“谁、从哪、连哪个库、用什么方式认证”,顺序敏感——匹配第一条即终止后续判断。错误地放在末尾或用了 trust 会导致未授权访问。
- 规则格式:
host <database><user><cidr-address><auth-method></auth-method></cidr-address></user></database> - 例如允许内网所有主机用密码连任意库:
host all all 192.168.1.0/24 md5 - 禁止某 IP:
host all all 203.0.113.42 reject - 避免使用
host all all 0.0.0.0/0 md5—— 这等于把密码验证当唯一防线,一旦密码泄露即全盘失守 - 改完执行
pg_ctl reload或SELECT pg_reload_conf();(需超级用户权限)
PostgreSQL 用户密码与认证方式的选择
即使配置了正确 IP 和监听,如果用户没设密码或认证方式不匹配,远程连接仍会失败。常见坑是沿用默认的 ident 或 peer 认证,它们依赖操作系统用户,对远程无效。
- 确认用户有密码:
ALTER USER postgres PASSWORD 'your_strong_password'; -
md5是最常用的安全选项:密码经 MD5 哈希后传输,服务端比对哈希值 -
password会明文传输密码(仅限本地可信网络),不推荐 -
scram-sha-256(PostgreSQL 10+)比md5更安全,需客户端支持;如用psql连接需加-c "set password_encryption = 'scram-sha-256'"初始化 - 检查当前用户认证方式是否被
pg_hba.conf中更早的规则覆盖(比如前面有一条local all all peer)
别忘了系统级和网络层限制
PostgreSQL 配置只是链路一环。很多连接失败其实卡在更外层:
- Linux 防火墙(
iptables/firewalld)是否放行5432端口?执行sudo firewall-cmd --add-port=5432/tcp --permanent && sudo firewall-cmd --reload - 云服务器(如腾讯云、AWS)安全组是否允许对应 IP 段访问
5432?这比数据库配置优先级更高 - SELinux 若启用,可能拦截 socket 绑定,临时关闭测试:
sudo setenforce 0 - 用
netstat -tlnp | grep :5432确认postmaster进程确实在监听你配置的地址,而非仍只绑127.0.0.1
真正容易被忽略的是:每改一次 pg_hba.conf 或 postgresql.conf,都必须 reload(或 restart),且 reload 不报错不代表规则生效——要实际用 psql -h <server_ip> -U <user></user></server_ip> 测试,同时看 PostgreSQL 日志(log_directory + log_filename 配置项所指位置)里的拒绝记录,那才是真实依据。










