# 08001 — 无法建立 SQL 连接（sqlclient_unable_to_establish_sqlconnection）

> PostgreSQL SQLSTATE 08001（无法建立 SQL 连接，sqlclient_unable_to_establish_sqlconnection）的源码证据、诊断与处理参考。
---

# 08001 — 无法建立 SQL 连接

## 速览 {#at-a-glance}

SQLSTATE `08001` 是 Class `08` 中的 **sqlclient_unable_to_establish_sqlconnection**。`08001` 是服务器端无法建立客户端连接时使用的 SQLSTATE。选定的 `dblink_connect` 路径 ERROR 主报文为 `could not establish connection`，拒绝端口原因放在动态 DETAIL 中；这与 dblink 句柄不存在的 08003，以及启动阶段的 28000、28P01、3D000 不同。

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `08001` |
| 条件名 | `sqlclient_unable_to_establish_sqlconnection` |
| 状态 | `有效` |
| 已知存在于 | `7.4` |
| 锁定快照 | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| 宏 | `ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION` |
| 别名 | `—` |

<!-- source facts: data/errcodes/08001.json -->
<!-- END SQLSTATE FACTS -->

## 含义 {#meaning}

服务器端 `dblink_connect` 路径在 libpq 无法打开目标远端端点时发出此码。固定诊断为 ERROR，主报文是 `could not establish connection`，端点和操作系统原因放在动态 DETAIL 中。它描述的是建立命名远端句柄，与句柄不存在的 08003，以及会话尚未建立就被拒绝的 28000 或 3D000 不同。

源码并不自行格式化 DETAIL：`dblink.c` 通过 `errdetail_internal("%s", msg)` 传递 libpq 已经组装好的错误字符串。因此，下面选定运行中的 18.6 拒绝端口文本（含主机、端口和 `Connection refused`）以及 10.21 的 libpq 文本都只是运行观察，不是 PostgreSQL 固定的 08001 模板。

## 诊断 {#diagnosis}

记录目标主机、端口、认证参数和完整 DETAIL。选定的 18.6/10.21 运行中，拒绝连接后本地自动提交会话保持 `IDLE`；随后用真实 dblink 句柄连到运行器实例，执行远端 `SELECT 1`，再显式断开。它证明本地恢复和句柄清理，不证明任何远端业务事务已经完成。

先判断失败阶段再重试。TCP 拒绝、DNS/TLS 失败和认证拒绝都可能由 libpq 通过这个 dblink 路径返回，必须查看动态 DETAIL，不能只按代码分类。若调用位于显式本地事务中，`ERROR` 可能使事务在 `ROLLBACK`（或 `ROLLBACK TO SAVEPOINT`）前不可继续；选定案例中的自动提交 `IDLE` 不能推广到显式事务。dblink 句柄属于创建它的后端，应在同一会话或同一个连接池成员中检查和修复。

## 处理 {#response}

修正端点或连接参数，建立新句柄并先验证无副作用的远端探针，再发送业务操作。若失败请求可能已经越过远端边界，重试前先对账；单凭 08001 不能重放非幂等操作。

自动提交时，修正端点后可以把建连当作新的语句重试，所有者会话仍可能可用。显式事务中应先恢复本地事务，再建立并探测新句柄；只有周围工作明确设计为可继续时，保存点才适合使用。若远端操作可能已经到达目标而本地只收到错误，重放前先核对结果。

## 实测诊断 {#messages}

固定的 `dblink_connect` 路径以 `ERROR` 发出主报文 `could not establish connection`，并通过 `errdetail_internal("%s", msg)` 传递动态 libpq 字符串。选定的 18.6 运行中该值为 `connection to server at "127.0.0.1", port 1 failed: Connection refused` 及 libpq 的后续提示；10.21 运行中则以 `could not connect to server: Connection refused` 开头。这些是运行特定值，不是固定 SQLSTATE 模板。其他 producer 可能使用不同文本；只有客户端异常而没有服务器诊断，不能据此认定此 SQLSTATE。

这个 dblink 路径的严重级别固定为 `ERROR`。选定本地会话使用自动提交，所以错误后仍为 `IDLE`；不要把这个状态推广到外层显式事务，或推广到未能确认结果的远端事务。

## 代表案例 {#case}

<!-- BEGIN SQLSTATE SNIPPET: dblink_connect_failure -->

此 SQL 块创建 `dblink`，尝试连接运行器本地的拒绝端口，然后探测所有者会话。触发点是服务器端 dblink 建连，不会在远端事务中执行工作。

`runner_host`、`runner_port`、`runner_db` 和 `runner_user` 是运行器占位参数，手工复制时不能照字面使用。应替换为可访问的目标和有权连接它的登录角色；安装/使用 `dblink` 以及远端登录都需要相应权限。若要复现选定的恢复观察，应在同一个所有者后端中按案例的自动提交边界执行这些语句。

```sql
CREATE EXTENSION IF NOT EXISTS dblink;
SELECT dblink_connect('missing_remote', 'host=127.0.0.1 port=1 dbname=postgres connect_timeout=1');
SELECT dblink_connect('working_remote', 'host=runner_host port=runner_port dbname=runner_db user=runner_user connect_timeout=5');
SELECT * FROM dblink('working_remote', 'SELECT 1') AS result(value integer);
SELECT dblink_disconnect('working_remote');
SELECT 1;
```

<!-- END SQLSTATE SNIPPET -->

18.6 运行记录 SQLSTATE 为 `08001`，主报文 `could not establish connection`；错误后所有者会话为 `IDLE`。修复打开句柄返回 `OK`，远端返回 `1`，断开返回 `OK`；最终探针返回 `1`，状态 `IDLE`。10.21 也通过同样断言。

可下载的案例与证据投影分别是 [`08001 案例 JSON`](../../data/cases/08001.json) 和 [`作者证据`](../../data/evidence/08001.json)。运行器清单为 `verify/cases/08001/cases.json`；发布前会将页面 SQL 与共享注册表比对。

## 版本 {#versions}

上面的生成事实表记录锁定的目录快照和最早观察到的定义。本页自然运行范围是 PostgreSQL 18.6 与 10.21，不能据此推断所有中间版本的行为。

## 相关 {#related}

- [`08000` — connection_exception](../08000/)
- [`08003` — connection_does_not_exist](../08003/)
- [`28000` — invalid_authorization_specification](../28000/)
- [`3D000` — invalid_catalog_name](../3d000/)

## 来源 {#sources}

- `src.dblink-connect.18.6` — `contrib/dblink/dblink.c` at `REL_18_6` commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`; fixed blob SHA-256 `e4cfaec3a0a1e5d23fded584725e0f6cf7a17321ad99e5fe046e8b7f97416f15` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/contrib/dblink/dblink.c#L335-L338)).
- `src.dblink-connect.10.23` — `contrib/dblink/dblink.c` at `REL_10_23` commit `02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4`; fixed blob SHA-256 `2d542cc722ba361bd59990aaed7fe7c0f8e147155df5e5fcd56ee03b4dd27c61` ([source](https://github.com/postgres/postgres/blob/02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4/contrib/dblink/dblink.c#L299-L302)).
- `src.calls.REL_18_6` / `src.calls.REL_10_23` — fixed local call scans, SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf` / `00d16d3eb01b71ccf1b245c8f3102f9d0ec9f36fb02777b8dd1b99fcb263040c`; these scans preserve the resolved call context used by the claims.
