先说结论,这个报错我没有当成普通的“连接失败”处理,而是把重点放在那个 "1" 上。看到 connection to server at "1", port 5432 failed "postgres" P 这种截断显示,十有八九是 localhost 被解析成了 IPv6 地址 ::1,而服务端只监听了 IPv4 的 127.0.0.1。简单说,客户端跑到了 IPv6 那扇门,门根本没开,于是连接被拒。
很多人在这一步会反复检查端口、用户名、密码,甚至重装 PostgreSQL,结果还是报错。其实问题不在“连不上”,而在“往哪里连”。这篇就围绕这个报错展开,把 PostgreSQL 连接链路里的监听配置、认证配置、驱动行为、常见变体全过一遍。不论你是刚装好 pgsql 第一次用 psql 连接,还是在 Windows 上给 .NET 项目配 Npgsql 连接串,只要能看懂这篇文章的排错思路,这类问题基本都能自己解决。
1. 报错拆解:"1" 根本不是你以为的那个字段
1.1 逐段解读 PostgreSQL 客户端的报错信息
先看这个报错的完整结构。PostgreSQL 客户端连接失败时,报错通常长这样:
code复制psql: error: connection to server at "localhost" (::1), port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
如果用的是某些图形化工具、连接池中间件,或者报错文本在传输中被截断,(::1) 可能显示成 ( :1),再往后截断就成了 "1"。所以在标题里看到的 at "1", port 5432,不是说你连接了一个叫 1 的主机,而是 localhost 被解析成了 IPv6 回环地址 ::1。
逐段拆解:
| 报错片段 | 含义 |
|---|---|
connection to server |
客户端尝试建立 TCP 连接 |
at "localhost" (::1) |
目标主机名是 localhost,解析后的 IP 是 IPv6 地址 ::1 |
port 5432 |
目标端口是 PostgreSQL 默认端口 5432 |
failed |
TCP 连接层失败,还没走到认证阶段 |
"postgres" |
客户端打算以 postgres 用户登录 |
Connection refused |
服务端没有进程在监听该地址+端口,或者防火墙直接拒绝了连接 |
最关键的一点:这个阶段连用户名都还没用上。凡是报错卡在 failed 这里,先别去怀疑密码和用户,你根本还没到那一步。
1.2 为什么 localhost 会变成 ::1
现代操作系统默认开启了 IPv6 协议栈,/etc/hosts 文件里通常同时存在这两行:
code复制127.0.0.1 localhost
::1 localhost
当客户端程序调用 getaddrinfo("localhost", ...) 解析主机名时,操作系统会返回一个地址列表。大多数优先返回 IPv6 地址(RFC 6724 的地址选择规则),客户端就会先尝试连接 ::1:5432。如果 PostgreSQL 服务端的 listen_addresses 只配置了 localhost 或者 127.0.0.1,服务端进程只监听了 IPv4 回环地址,那对 IPv6 回环地址 ::1 的连接自然会被拒绝。
直接验证方法很简单。在命令行分别执行:
bash复制psql -h localhost -U postgres -d postgres
# 报错:connection to server at "localhost" (::1), port 5432 failed
psql -h 127.0.0.1 -U postgres -d postgres
# 如果这个能正常连接,问题就确认了:IPv6 监听缺失
我曾经在一台 Ubuntu 服务器上排查过类似问题,psql -h 127.0.0.1 秒连,psql -h localhost 必失败。用 ss -tlnp 一看,5432 端口只监听在 127.0.0.1 上,没有 :::5432。这种情况不修改配置,不管怎么重试都不可能连上 localhost。
提示:看到
"1"这种“半截地址”,优先怀疑 IPv6 地址::1被显示层截断,而不是真的有个主机名是1。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么改了不少配置还是连不上:监听与认证是两回事
2.1 postgresql.conf:listen_addresses 决定服务端开哪扇门
PostgreSQL 的 postgresql.conf 里,listen_addresses 控制服务端监听哪些 IP 地址。默认值是 'localhost',意味着只监听回环地址,而且具体监听 IPv4 还是 IPv6,取决于 PostgreSQL 编译时是否启用 IPv6,以及系统网络栈配置。
常见的几种配置:
ini复制# 只监听 IPv4 回环
listen_addresses = '127.0.0.1'
# 只监听 IPv6 回环
listen_addresses = '::1'
# 监听本机所有 IPv4 和 IPv6 地址
listen_addresses = '*'
# 监听多个具体地址
listen_addresses = '127.0.0.1,192.168.1.100,::1'
如果你需要本地通过 localhost 连接,同时又要让局域网内其他机器访问,最省事的写法是 listen_addresses = '*',然后靠防火墙来控制访问范围。不过要注意,* 包含所有网卡地址,如果服务器有多个 IP,全部都会暴露,生产环境建议明确写出需要监听的 IP。
修改完 postgresql.conf 之后,必须要重启服务,reload 对 listen_addresses 不生效。这是很多人踩过的坑:
bash复制# 传统 sysvinit 风格
sudo systemctl restart postgresql
# 或者按版本指定
sudo systemctl restart postgresql@14-main
重启之后再确认:
bash复制ss -tlnp | grep 5432
如果输出里有 *:5432 或者 0.0.0.0:5432 和 [::]:5432,说明监听已经放开。
2.2 pg_hba.conf:即使监听放开了,认证也可能把你挡在门外
监听地址解决的是“网络能不能到”,而 pg_hba.conf 决定的是“你这个人能不能进”。它在 PostgreSQL 数据目录下,默认位置在 Linux 是 /etc/postgresql/<版本>/main/pg_hba.conf,Windows 是 C:\Program Files\PostgreSQL\<版本>\data\pg_hba.conf。
常见认证方式:
| 方法 | 说明 | 常见场景 |
|---|---|---|
trust |
不验证密码,只要 IP 匹配就放行 | 开发环境、本机调试 |
peer |
使用操作系统用户名作为数据库用户名,仅限本机 Unix socket | Linux 默认本地连接 |
md5 |
密码以 MD5 加密传输 | 老版本兼容 |
scram-sha-256 |
密码以 SCRAM 机制加密传输,更安全 | PostgreSQL 10+ 默认推荐 |
如果 pg_hba.conf 里配置了 local all postgres peer,那么用 psql -U postgres 走 Unix socket 时,PostgreSQL 会检查当前操作系统用户,只有系统用户是 postgres 才能连。普通用户直接连会报:
code复制FATAL: Peer authentication failed for user "postgres"
如果是 TCP 连接(host 行),默认要求密码认证。Windows 安装器生成的 pg_hba.conf 通常在本机也要求密码,用 postgres 用户时如果密码输错或不对,就会报:
code复制FATAL: password authentication failed for user "postgres"
这时先去确认 pg_hba.conf 里对应行使用的是哪种认证方式,再决定是改配置还是改连接方式。
提示:排错时先分清报错阶段。
Connection refused是网络层问题,FATAL: password authentication failed是认证层问题,两层的排查方向完全不同。
3. 一次从“完全连不上”到“正常连接”的完整排查
3.1 阶段一:确认服务状态和端口监听
遇到连接失败,第一反应不是改配置,而是先确认服务真的在跑。我见过不少案例,所谓“PostgreSQL 连接失败”其实是服务根本没启动,或者服务启动后又崩了。
Linux 下查看服务状态:
bash复制systemctl status postgresql
ps aux | grep postgres
确认进程存在后,再看端口监听:
bash复制ss -tlnp | grep 5432
可能输出:
code复制LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=12345,fd=7))
或者:
code复制LISTEN 0 200 [::1]:5432 [::]:* users:(("postgres",pid=12345,fd=7))
关键信息在本地地址那一列。如果只有 127.0.0.1:5432,IPv6 的 ::1 自然连不上;如果只有 [::1]:5432,IPv4 的 127.0.0.1 反而连不上。两者都监听时,才能统一处理 localhost 的两种解析结果。
Windows 下查看端口监听:
bat复制netstat -ano | findstr 5432
如果看到 127.0.0.1:5432,同样说明只监听了 IPv4。Windows 下修改 postgresql.conf 后,需要在服务管理器中重启 postgresql-x64-14 这类服务。
3.2 阶段二:用多种地址分别测试,缩小问题范围
定位监听了什么地址之后,用不同主机名和地址分别测试:
bash复制# 测试 IPv4 回环
psql -h 127.0.0.1 -U postgres -d postgres
# 测试 IPv6 回环
psql -h ::1 -U postgres -d postgres
# 测试操作系统解析后的 localhost
psql -h localhost -U postgres -d postgres
三种测试结果对照:
| 测试命令 | 可能结果 | 结论 |
|---|---|---|
-h 127.0.0.1 |
成功 | IPv4 监听正常 |
-h 127.0.0.1 |
失败 | IPv4 监听缺失或认证失败,继续看报错 |
-h ::1 |
成功 | IPv6 监听正常 |
-h ::1 |
失败 | IPv6 监听缺失或防火墙拦截 |
-h localhost |
失败但 -h 127.0.0.1 成功 |
解析走了 IPv6,但服务端没监听 IPv6 |
上面最后一行的情况,和标题里的报错完全吻合。之前我处理过一个开发服务器,psql -h localhost 稳定复现失败,查 ss -tlnp 发现 PostgreSQL 只监听了 IPv4。把 listen_addresses 从 'localhost'(很多场景下只绑定 IPv4 回环)改成 '127.0.0.1,::1' 并重启后,问题立刻消失。
还有一种隐藏情况:PostgreSQL 编译时没带 IPv6 支持,此时即使 listen_addresses 写了 ::1,也无法监听 IPv6。这种场景比较少见,如果服务器是旧系统或特殊发行版仓库里的二进制包,值得留意。
3.3 阶段三:修改配置、重启服务、验证结果
确认问题出在 IPv6 监听缺失后,修改 postgresql.conf:
ini复制listen_addresses = '127.0.0.1,::1'
如果这只是开发环境,直接用 '*' 更省心。然后重启服务:
bash复制sudo systemctl restart postgresql
再用 ss -tlnp 检查:如果同时看到 127.0.0.1:5432 和 [::1]:5432,说明两个回环地址都在监听了。此时再执行:
bash复制psql -h localhost -U postgres -d postgres
应该能正常进入交互界面。如果还报错,再看 pg_hba.conf 的认证配置,确认密码认证方式是否匹配。
提示:改任何
postgresql.conf或pg_hba.conf之前,先备份原文件。改完用pg_ctl reload可以热加载pg_hba.conf,但listen_addresses必须重启。
4. 报错变体:同一个根因,不同马甲
4.1 could not translate host name "1" to address:主机名解析失败
这个报错和标题里的情况经常一起出现,形式是:
code复制psql: error: could not translate host name "1" to address: Name or service not known
说明客户端把 1 当成主机名去解析,但系统里根本没有这个主机名。常见原因有两个:
第一,连接串里主机名写错。比如某个脚本中连接串写成:
code复制postgresql://postgres:password@1:5432/mydb
这里的 1 可能是变量没有正确传值,或者本意是 127.0.0.1 被截断了。检查连接串的生成逻辑,确认主机名部分完整。
第二,IPv6 字面量没有加方括号。PostgreSQL 连接串里,主机名用 IPv6 地址时必须写成:
code复制postgresql://postgres:password@[::1]:5432/mydb
如果漏掉方括号,客户端会把 ::1 当成畸形主机名,解析失败。
4.2 FATAL: role "postgres" does not exist:用户名和目标实例对不上
这个报错发生在认证阶段之后,服务端已经接受了连接请求,但在查找用户时发现没有对应角色。
code复制FATAL: role "postgres" does not exist
常见场景:
- 初始化数据库时指定了其他超级用户。比如用
initdb -U admin初始化,那超级用户名就是admin,没有postgres角色。 - 连接到了错误的实例。机器上装了多个 PostgreSQL 版本或实例,默认端口被某个实例占用,而你想连的那个实例在另一个端口。
- 客户端驱动/工具自动填充了
postgres作为用户名。比如某些 IDE 默认用户名是postgres,但实际数据库里没这个用户。
排查方式:
bash复制# 列出当前实例的所有角色
sudo -u postgres psql -c "\du"
如果确实没有 postgres,可以用现有超级用户创建:
sql复制CREATE ROLE postgres WITH LOGIN SUPERUSER PASSWORD 'your_password';
4.3 server does not support SSL 和 sslmode 相关报错
这个变体在客户端工具和驱动里也常见:
code复制psql: error: server does not support SSL, but SSL was required
PostgreSQL 服务端如果编译时没启用 SSL,或者没有配置证书,客户端却要求 SSL 连接,就会报这个错。psql 默认 sslmode=prefer(优先使用 SSL,但不强制),一般不会报错;但如果连接串里显式写了 sslmode=require,服务端不支持时就会失败。
解决方式取决于你想怎么处理:
- 连接串里改为
sslmode=disable,明文连接,仅限可信内网环境。 - 在服务端启用 SSL,配置
ssl = on、ssl_cert_file、ssl_key_file,然后重启。
Npgsql(.NET 驱动)也有类似行为:默认 SSL Mode=Prefer,新版在某些环境下会变成 Require。我在 Windows 上遇到过一个老项目,连接串里没写 SSL 配置,Npgsql 尝试 SSL 握手失败后报 connection failed: error sending request,后来在连接串里加上 SSL Mode=Disable 才解决。
提示:
error sending request这类“发送请求失败”的报错,在网络驱动层出现时,未必是 PostgreSQL 本身的问题。如果服务器能 ping 通但驱动报错,优先查防火墙、SSL 握手、负载均衡超时这几个点。
5. 还没结束:客户端驱动、连接池、容器环境都在捣乱
5.1 Npgsql 连接串的 SSL 和权限问题
在 Windows 上用 C# 连接 PostgreSQL(比如 SQL Server 迁移过来的项目,想试试开源数据库),最常用的驱动是 Npgsql。它的连接串和 psql 命令行参数不完全一样,出问题的时候报错也更“抽象”。
Npgsql 连接串示例:
code复制Host=localhost;Port=5432;Username=postgres;Password=123456;Database=mydb;SSL Mode=Disable;
这个连接串在本地开发时很稳。但如果你把 Host=localhost 换成 Host=127.0.0.1,效果也一样,绕开了 IPv6 解析。如果是远程服务器,Host 要写成服务器的公网/内网 IP。
Npgsql 常见的连接失败类问题:
| 报错信息 | 原因 | 处理 |
|---|---|---|
Exception while connecting |
网络不通、端口未监听 | 检查服务端监听和防火墙 |
The SSL connection could not be established |
服务端 SSL 配置不完整 | SSL Mode=Disable 或配置证书 |
28000: password authentication failed |
用户名或密码错误 | 核对密码,检查 pg_hba.conf |
3D000: database "xxx" does not exist |
数据库名写错 | 用 \l 查看已有数据库 |
另外,Npgsql 有连接池机制。如果服务端重启过,池里缓存的连接失效,程序首次报错后重试可能恢复。如果频繁出现“连接已关闭”但数据库正常,可以考虑设置 Connection Idle Lifetime 和 Connection Pruning,让池里的过期连接及时清理。
5.2 连接池和服务端 keepalive:为什么“跑一段时间才报错”
一个很常见的坑是:程序刚启动连接正常,跑一段时间后突然报连接失败,重启应用又正常。这不是标题里那个报错的直接形态,但如果你在排查过程中遇到“间歇性连接失败”,多半和连接池/keepalive 有关。
PostgreSQL 服务端默认的 tcp_keepalives_idle、tcp_keepalives_interval 可能让空闲连接被中间设备(防火墙、云负载均衡)断开。客户端连接池持有这些“死连接”,取出来用时才发现连不上。
一个简单的验证方法:在服务端查看连接状态:
sql复制SELECT pid, state, backend_start, state_change FROM pg_stat_activity;
如果发现很多连接是 idle,但客户端实际已断,可以调大客户端的超时重试机制,或者在服务端设置 tcp_keepalives_idle = 60 等参数,让检测更主动。
如果你用的是云数据库(RDS 这类),它前面通常有代理或负载均衡,默认空闲连接超时更短。客户端连接串里尽量加上 keepalive 相关参数,或者用连接池的保活机制定期发送查询。
5.3 Docker 和宝塔面板:localhost 的“空间错位”
在 Docker 容器里运行 psql 客户端时,localhost 指向容器自己,而不是宿主机。如果 PostgreSQL 服务跑在宿主机上,容器内执行:
bash复制psql -h localhost -U postgres
实际上连接的是容器自己的 5432 端口,大概率什么都没有,于是报连接失败。正确做法是用宿主机 IP(比如 172.17.0.1 这种 Docker 网关地址),或者用 --network host 启动容器直接共享宿主网络。
如果你用宝塔面板管理 PostgreSQL,在面板里“无法备份 pgsql”或“连接失败”也是常见问题。宝塔的 PHP/Python 环境可能需要额外安装 pgsql 扩展,面板自带的数据库管理功能有时和系统里手动装的 PostgreSQL 实例端口冲突。排查方式:
- 确认面板识别的是哪个数据库实例和端口。
- 命令行手动连接:
psql -h 127.0.0.1 -p 5432 -U postgres -d postgres。 - 如果命令行能连但面板不能,检查面板进程和数据库之间的网络权限,以及是否为面板用户配置了数据库访问权限。
提示:凡是“换了一个工具就连不上”的情况,先回到命令行手动连接。命令行是最低层、最少干扰的验证方式,能连说明数据库本身没问题,问题在工具或驱动配置上。
6. 个人经验:把连接问题挡在发生之前
6.1 连接统一用显式 IP 或主机名,而不是 localhost
吃了太多 localhost 的亏之后,我现在写连接串的原则是:开发环境能写 127.0.0.1 就不写 localhost,能用具体主机名就不写模糊别名。原因很简单,localhost 在不同操作系统、不同网络配置下解析结果不一致,而 127.0.0.1 永远是 IPv4 回环,行为可预测。
如果必须用主机名,先在命令行验证一下解析结果:
bash复制getent hosts localhost
# 或 Windows 下
nslookup localhost
确认解析出来的 IP 和你预期一致,再写进配置文件或连接串里。
6.2 日志是排错的第一入口,别靠猜
PostgreSQL 的日志默认记录很多连接信息。Linux 下日志一般在 /var/log/postgresql/postgresql-<版本>-main.log,Windows 下可以通过 pg_log 目录找到。
连接失败时,服务端日志会记录更精确的原因,比如:
code复制LOG: incomplete startup packet
FATAL: no pg_hba.conf entry for host "::1", user "postgres", database "postgres", SSL off
这比客户端报错信息有用得多。客户端只告诉你“连不上”,服务端日志告诉你“从哪个地址来、用什么用户、想连哪个库、卡在哪一步”。
6.3 维护一份连接排错清单
这几年的经验告诉我,PostgreSQL 连接问题大部分都能归到以下几类,排查时按顺序走就行:
- 网络可达性:ping 通吗?telnet 目标端口通吗?
bash复制
telnet 127.0.0.1 5432 - 服务状态和监听地址:进程活着吗?端口监听在哪个地址?
- 防火墙和安全组:本地通、远程不通时重点查。
- pg_hba.conf 认证规则:从哪个 IP 来、用什么用户、走什么认证方式,逐行对上。
- 用户名和密码:角色是否存在,密码是否匹配,认证方式是否支持该密码协议。
- SSL 参数:两端 SSL 配置是否兼容。
- 驱动和连接池:连接串参数是否正确,池内是否有残留旧连接。
这套清单看起来简单,但每次排错都按顺序走一遍,能省掉大量“猜测式修配置”的时间。尤其是面对标题里那种 "1" 截断显示,不按链路过一遍,很容易在错误的方向上越走越远。
