PostgreSQL连接字符串URI并不是一段可以随意拼接的文本,它由客户端库按照RFC 3986的通用URI语法解析,解析顺序决定了哪些字符需要转义、哪些参数会影响连接行为。弄清这套格式,对排查连接失败、配置读写分离和保证密码安全都有实际意义。

一、URI基础结构和各部分含义
PostgreSQL标准连接串通常以 postgresql:// 或 postgres:// 开头,二者等价。完整形态可以写成:
postgresql://[user[:password]@][host][:port][/dbname][?param1=value1¶m2=value2]
方括号表示可选段。解析器会先识别 scheme,然后从 @ 符号拆分用户信息和主机信息;如果存在 /,则数据库名开始;如果存在 ?,后面的键值对交给连接参数解析器处理。一个完整例子如下:
postgresql://alice:p%40ss@db.ipipp.com:5432/orders?sslmode=require&connect_timeout=10
这里 alice 是用户名,原始密码是 p@ss,但 @ 被编码为 %40,db.ipipp.com 是主机,5432 是端口,orders 是数据库名,sslmode 和 connect_timeout 是两个连接参数。缺少端口时,PostgreSQL 默认使用 5432;缺少数据库名时,多数客户端会尝试使用与用户名同名的数据库。
有些环境还会出现 postgresql://user@/dbname 这种写法,空主机段表示使用默认的本地 Unix 套接字。这种格式在 libpq 和大多数兼容驱动中有效,但 JDBC 的解析规则略有不同,通常不推荐在跨语言项目中混用。
二、查询参数和百分号编码规则
连接参数位于问号之后,使用 key=value 形式,多个参数用 & 符号分隔。常见参数包括 sslmode、connect_timeout、application_name、options 和 target_session_attrs。sslmode 控制 TLS 校验级别,可选 disable、allow、prefer、require、verify-ca、verify-full;connect_timeout 单位是秒,控制建立 TCP 连接的超时时间;application_name 会显示在 pg_stat_activity 中,方便定位应用来源;options 可以传递服务端参数,例如语句超时;target_session_attrs 用于多主机场景,取值 any、read-write、read-only、primary、standby 等。
URI 中的保留字符包括 @、/、?、#、:、[、] 和空格。当用户名或密码包含这些字符时,必须进行百分号编码,否则解析器会在错误的位置切分字符串。最常见的错误是密码含 @,如果不编码,客户端会误以为 @ 前面是用户名和密码,@ 后面是主机,导致主机解析失败。比如原始密码为 p@ss:/word#,编码后应写成 p%40ss%3A%2Fword%23:
# 原始密码:p@ss:/word# # 编码后:p%40ss%3A%2Fword%23 postgresql://app:p%40ss%3A%2Fword%23@db.ipipp.com/appdb
参数值中出现空格时同样需要编码,例如 options=-c statement_timeout=30000 应写成 options=-c%20statement_timeout%3D30000,避免空格和等号干扰查询参数解析。不同驱动对未编码空格的容忍度不一致,建议统一编码。
另一个容易被忽略的场景是 Unix 域套接字路径。标准 TCP 连接可以直接写主机名或 IP,但本地连接要写成 host=/var/run/postgresql,斜杠在问号后的参数值中通常可以保留,但某些严格实现要求编码为 %2Fvar%2Frun%2Fpostgresql。完整串形如:
postgresql:///appdb?host=%2Fvar%2Frun%2Fpostgresql
这种写法以三个斜杠开头,空主机段配合 host 参数指定套接字目录。各发行版的默认套接字目录不同,常见路径包括 /var/run/postgresql 和 /tmp,使用前需要确认实际目录。
三、多主机、IPv6 和读写分离配置
当数据库采用一主多备架构时,可以在 URI 中用逗号分隔多个主机,每个主机可以单独带端口。客户端会按顺序尝试连接,默认选择第一个可用的服务器。例如:
postgresql://user:pass@pg-primary:5432,pg-replica:5432/appdb?target_session_attrs=read-write&connect_timeout=5
如果把 target_session_attrs 设为 read-write,客户端会跳过只读备机,只接受能够执行读写事务的主节点。这个机制在做故障转移时很有用,但要注意不同 PostgreSQL 版本和客户端库对 primary、standby 等取值的支持存在差异,libpq 较新版本才完整支持这些语义。
IPv6 地址必须用方括号包裹,否则冒号会被误认为端口分隔符。例如:
postgresql://user:pass@[2001:db8::1]:5432/appdb
如果 IPv6 地址不写方括号,解析器会尝试把 2001 当主机名,把 db8 当端口,导致连接失败。对于纯 IPv6 网络,还需确认服务端 listen_addresses 已包含对应地址。
Unix 套接字除了通过 host 参数指定,一些客户端也支持把套接字目录放在主机位置,但写法更容易混淆,不建议在通用配置中使用。需要明确的是,Unix 套接字连接不经过 TCP 层,因此 TCP 端口和 sslmode 通常不会生效,调试时要注意连接实际走的是套接字文件还是网络端口。
四、常见错误排查与安全建议
连接串无法工作时,可以先从解析结果入手。使用 psql 直接传入同一 URI,观察报错信息;如果 psql 能连通而应用连不通,问题多半出在驱动或配置转义上。例如在 YAML、XML 等配置文件中,& 符号需要写成 &,否则参数会在加载阶段被截断。下面是一个命令行验证示例:
psql "postgresql://alice:p%40ss@db.ipipp.com/appdb?sslmode=require"
另一个常见问题是密码包含 #。在 URL 中 # 表示 fragment 起始,浏览器或部分客户端会忽略 # 后面的内容,因此必须编码为 %23。如果使用自动化脚本拼接连接串,应统一对 user 和 password 做百分号编码,不要手动拼接未处理的原始值。
安全方面,连接串中的 userinfo 属于敏感信息。即使启用了 TLS,连接串本身仍可能出现在进程参数、环境变量、日志或监控平台中。建议优先使用 pgpass 文件、环境变量或密钥管理系统保存密码,仅在必要场景下才把密码放进 URI。如果必须内嵌密码,应避免在应用日志中打印完整连接串,并对配置中心或容器编排中的变量做加密存储。
还需留意 sslmode=verify-full 与主机名匹配问题。如果 URI 中使用 IP 连接,但证书只签发了域名,verify-full 会校验失败;此时要么改用证书覆盖的域名,要么在测试环境显式降低校验级别,但生产环境不建议长期使用 require 以下的安全级别。连接参数虽然灵活,但每一项都直接影响连接建立方式,配置时应明确每个参数的真实效果。
PostgreSQL连接字符串数据库URI连接参数修改时间:2026-10-01 08:38:38