
当 PostgreSQL 连接 URL 中的密码包含 @、$、/ 等 URL 保留字符时,未编码会导致解析失败,引发 Name or service not known 错误;需使用 urllib.parse.quote() 对密码进行 URL 编码后拼接连接字符串。
当 postgresql 连接 url 中的密码包含 `@`、`$`、`/` 等 url 保留字符时,未编码会导致解析失败,引发 `name or service not known` 错误;需使用 `urllib.parse.quote()` 对密码进行 url 编码后拼接连接字符串。
在使用 psycopg_pool.ConnectionPool 初始化连接池时,若 conninfo 字符串中密码含有 @、$、:、/ 或 % 等 URL 特殊字符,而未做 URL 编码,PostgreSQL 驱动会错误地将 @ 视为用户名与主机地址的分隔符,从而把密码的一部分误解析为主机名(例如 password@host 被截断为 password 作密码、host 前多出一段非法域名),最终触发系统级报错:[Errno -2] Name or service not known —— 这本质是 DNS 解析失败,根源却是连接字符串格式不合法。
✅ 正确做法:对密码单独编码,再安全拼接 URL。推荐使用 urllib.parse.quote() 并指定 safe=''(避免对 / 等必要分隔符误编码):
from urllib import parse
from psycopg_pool import ConnectionPool
# 原始敏感密码(含 @ 和 $)
raw_password = "my@pass$word123"
# ✅ URL 编码密码(保留空格编码为 %20,不编码 / : @ 等关键符号)
encoded_password = parse.quote(raw_password, safe='')
# 构建合规 conninfo(注意:其他部分如 username、host、port、dbname 不应编码)
conninfo = f"postgresql://username:{encoded_password}@ipaddress:5432/database"
# 使用连接池(确保 max_size、kwargs 等配置合理)
with ConnectionPool(
conninfo=conninfo,
max_size=app.config["DB_MAX_CONNECTIONS"],
kwargs=connection_kwargs,
) as pool:
# ... use pool
pass⚠️ 注意事项:
- ❌ 不要对整个连接字符串调用
quote(),否则@、:、/等分隔符会被破坏,导致语法错误; - ✅ 只对密码字段(及必要时 username)做编码,且
safe=''是关键(默认safe='/'会保留/不编码,但密码中一般不含/;若含/,则必须设safe=''并确保其不会干扰 URL 结构); - 若密码来自配置项(如
app.config["DB_PASSWORD"]),务必在构造conninfo前完成编码,而非依赖环境变量“自动处理”; - 验证方式:打印编码后的
conninfo,确认形如postgresql://user:my%40pass%24word123@...,其中@→%40,$→%24。
总结:URL 中的密码不是普通字符串,而是 URI 组成部分,必须遵循 RFC 3986 编码规范。看似相同的 psql 命令能连通,是因为 psql 内部做了隐式转义或支持交互式输入,而 psycopg 的连接池严格按 URI 解析——因此,显式、精准的密码编码是生产环境稳定连接的必要实践。

















