# 28P01 — invalid_password（密码无效）

> 密码认证在连接启动阶段失败时，PostgreSQL 会报告 SQLSTATE 28P01。应检查匹配的 pg_hba.conf 规则和角色密码，并用新的连接证明修复。
---

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

`28P01` 是 PostgreSQL 类别 28 `invalid_authorization_specification` 中的 `invalid_password` 条件。客户端建立会话时密码认证失败，会产生这个代码。具体路径取决于认证方法、匹配的 `pg_hba.conf` 规则和角色保存的密码。

这是 SQL 执行前的失败。被拒绝的会话没有事务可供回滚。最终运行中，psycopg 返回了启动异常文本，但暴露的 `sqlstate` 为 `None`；PostgreSQL collector 记录了服务器实际发送的 `FATAL` SQLSTATE `28P01`。不能把没有代码的驱动异常描述成客户端收到了 collector 字段。

案例 `wrong_password_authentication` 临时启用 `md5` 规则，使用错误密码连接，验证已知密码可以建立新会话并执行 `SELECT 1`，恢复原来的 HBA 配置，再验证新的管理连接。案例在 PostgreSQL 18.6 和隔离的 PostgreSQL 10.21 上均通过。run ID 和断言见[公开证据 JSON](../../data/evidence/28p01.json)。

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

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `28P01` |
| 条件名 | `invalid_password` |
| 状态 | `有效` |
| 已知存在于 | `9.0.0` |
| 锁定快照 | `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_INVALID_PASSWORD` |
| 别名 | `—` |

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

## 含义与触发路径 {#meaning}

服务器根据第一条匹配的 `pg_hba.conf` 规则选择认证方法。密码、MD5 和 SCRAM 路径拒绝提交的密码时，`auth.c` 选择 `ERRCODE_INVALID_PASSWORD` 并报告 `FATAL`。主报文模板是 `password authentication failed for user "%s"`；服务器也可以在日志 detail 中加入匹配的 HBA 信息。

`28P01` 不会区分所有认证配置问题。角色不存在、角色不允许登录、证书失败，或 HBA 规则选择了其他方法，都可能使用不同的 SQLSTATE 或报文。匹配的规则和认证方法是诊断的一部分。

失败发生在连接启动阶段，后端尚未接受 SQL。连接池应丢弃被拒绝的连接尝试，在密码或 HBA 配置修好后建立新的连接。仍在使用的所有者或管理连接可以恢复临时规则，但复用它们不能证明受影响角色可以认证。

## 报文与诊断 {#messages}

下面的 SQL 语句与 runner 使用的密码设置和探针相同。运行时 `known_user` 和 `example-known-secret` 会替换为临时值。修改 `pg_hba.conf` 和使用错误密码建立连接属于启动操作，因此在 SQL 语句之间说明，而不是伪造 `RAISE` 或 SQL 错误。

<!-- BEGIN SQLSTATE SNIPPET: wrong_password_authentication -->
```sql
ALTER ROLE known_user PASSWORD 'example-known-secret';
-- 在 pg_hba.conf 首行临时加入 host all all 0.0.0.0/0 md5。
-- 使用错误密码以 known_user 连接：启动阶段返回 FATAL 28P01。
-- 再使用已知密码建立连接并执行：
SELECT 1;
-- 恢复原 pg_hba.conf，建立新的管理连接并执行：
SELECT 1;
```
<!-- END SQLSTATE SNIPPET -->

最新目标的 collector 记录形状为：

```text
SQLSTATE: 28P01
severity: FATAL
message_primary: password authentication failed for user "<generated-role>"
detail (collector): Connection matched file "<pg_hba.conf path>" line 1: "host all all 0.0.0.0/0 md5"
source: auth.c / auth_failed / line 320
driver startup sqlstate: null
transaction: none opened
repair: known-password SELECT 1 -> 1; restore HBA; fresh owner SELECT 1 -> 1
```

PostgreSQL 10.21 的 collector 产生相同的主报文和 SQLSTATE，源码位置为 `auth.c:329`；其 collector detail 使用较早的 `pg_hba.conf line` 表述，并且还包含密码不匹配行。两个目标都在临时规则下用已知密码认证成功，重新加载原 HBA 配置，并让新的管理连接返回 `1`。驱动文本和 collector 字段是两条独立证据；本次运行中 libpq/psycopg 没有暴露启动 SQLSTATE。

## 诊断 {#diagnosis}

记录用户、数据库、连接来源、认证方法、服务器版本和第一条匹配的 HBA 规则，不要记录密码。按时间关联失败尝试和 verbose collector 记录。collector detail 可以指出 HBA 行，而客户端启动异常可能只有 FATAL 文本。

检查目标角色存在且允许登录，密码已针对选定方法设置，并确认更早的 HBA 规则没有截获连接。正确密码配在错误的 HBA 方法上不能证明部署正确。密码轮换完成前，应等待新的连接成功。

被拒绝的会话没有事务状态需要恢复。修改 HBA 规则时保留受控的管理连接，重新加载配置，并用新的客户端测试。测试完成后精确恢复原规则，再确认新的所有者连接仍可用。

## 处理与修复 {#response}

- 为角色使用预期的密码和认证方法，通过不会把密码暴露到日志或命令历史的途径轮换密码。
- 检查第一条匹配的 `pg_hba.conf` 规则，修正数据库、用户、地址和方法字段，然后重新加载配置。
- 用新的连接和真实的无害查询（例如 `SELECT 1`）测试受影响角色。
- 在新路径得到证明前保留管理访问，随后关闭仍保存旧密码的连接池陈旧会话。

代表性修复同时包含已知密码连接和恢复后的新管理连接。仅成功调用 `pg_reload_conf()` 不能证明认证已经修好，复用执行 reload 的连接也不能测试修复后的登录路径。

## 版本与边界 {#versions}

目录在第一份扫描到的定义（`9.0.0` 或更早）中已包含 `28P01`，并在列出的所有正式快照直到 PostgreSQL 18.6 以及 PostgreSQL 19 Beta 3 预览中存在。扫描范围内没有记录该条件的定义变化；9.0 以前的引入点仍未扫描。

错误密码案例在 PostgreSQL 18.6 和 10.21 上通过。源码行号随版本变化，驱动与 collector 的 SQLSTATE 差异是本启动路径的实测边界。证书、GSSAPI、PAM、LDAP、peer 和 HBA 语法失败是独立认证路径，本证据不覆盖。

## 相关 {#related}

[`53300` — `too_many_connections`](../53300/) 是连接启动阶段的容量失败。[`57014` — `query_canceled`](../57014/) 发生在已连接后端执行语句时。[`42501` — `insufficient_privilege`](../42501/) 是认证后的权限检查，不是密码诊断。

## 来源 {#sources}

结构化证据记录在[公开证据 JSON](../../data/evidence/28p01.json)中。源码记录固定到 PostgreSQL commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`；运行记录保留 collector 输出、驱动观察、HBA 恢复、两个目标 ID 和结构化观察。

- `src.errcodes.18.6` — [`errcodes.txt`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L271-L278)
- `src.auth.18.6` — [`auth.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/libpq/auth.c#L270-L332)
- `doc.client-auth.18` — [pg_hba.conf 文件](https://www.postgresql.org/docs/18/auth-pg-hba-conf.html) 与 [密码认证](https://www.postgresql.org/docs/18/auth-password.html)
- `doc.protocol.18` — [错误和通知消息字段](https://www.postgresql.org/docs/18/protocol-error-fields.html)
- Runtime：latest 与 pg10 均为 `28P01-registry-final-20260909`，结构化观察见[公开证据 JSON](../../data/evidence/28p01.json)
