↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

Wiki / SQLSTATE

28P01 — invalid_password(密码无效)

建立会话时密码认证失败,连接被拒绝。

英文手册覆盖始于 PostgreSQL 8.1. 来源历史与运行验证各自保留独立版本边界。

当前阅读 PG 18·选择有来源记录的版本

aliases
未知
class name
Invalid Authorization Specification
condition name
invalid_password
lang
en
sqlstate
28P01

版本定义 PG 18

速览 {#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。

含义与触发路径 {#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 错误。

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;

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

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 是连接启动阶段的容量失败。57014 — query_canceled 发生在已连接后端执行语句时。42501 — insufficient_privilege 是认证后的权限检查,不是密码诊断。

来源 {#sources}

结构化证据记录在公开证据 JSON中。源码记录固定到 PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7;运行记录保留 collector 输出、驱动观察、HBA 恢复、两个目标 ID 和结构化观察。

比较版本

SQLSTATE 证据与已记录的运行版本

cases · wrong_password_authentication
{
  "assertions": [
    "The connection attempt receives SQLSTATE 28P01",
    "The server does not open a transaction for the rejected connection",
    "The known password opens a new session while the temporary rule is active",
    "A fresh management connection succeeds after the original configuration is restored"
  ],
  "case_id": "wrong_password_authentication",
  "cleanup": "Restore pg_hba.conf and drop the role and schema.",
  "has_snippet": true,
  "position": 0,
  "preconditions": [
    "A disposable login role with a known password",
    "A temporary first pg_hba.conf rule uses md5 and is reloaded"
  ],
  "repair": "Use the intended secret and authentication method, verify a new connection, then restore or rotate credentials without logging passwords.",
  "trigger": "Connect with a wrong password and retain the server's authentication diagnostic.",
  "versions": [
    "10",
    "18"
  ]
}
claims · identity.class-and-condition
{
  "claim_id": "identity.class-and-condition",
  "limits": "Directory identity does not identify the selected authentication method or the matched HBA rule.",
  "method": "Read the Class 28 section and 28P01 row in the frozen errcodes.txt snapshot.",
  "position": 0,
  "runtime": [],
  "sources": [
    "src.errcodes.18.6"
  ],
  "statement": "28P01 is the invalid_password condition in Class 28 invalid_authorization_specification."
}
claims · mechanism.auth-failure
{
  "claim_id": "mechanism.auth-failure",
  "limits": "Other authentication methods and HBA configuration errors use separate branches and can report different SQLSTATEs or messages.",
  "method": "Trace auth_failed's password/MD5/SCRAM error selection and detail construction and compare the official HBA and password-authentication rules.",
  "position": 1,
  "runtime": [],
  "sources": [
    "src.auth.18.6",
    "doc.client-auth.18"
  ],
  "statement": "The password authentication failure path in auth.c selects ERRCODE_INVALID_PASSWORD, reports password authentication failed for user \"%s\" at FATAL, and may add the matched pg_hba.conf line to log detail."
}
claims · runtime.driver-collector-boundary
{
  "claim_id": "runtime.driver-collector-boundary",
  "limits": "Driver exposure can vary by client and startup failure; the collector record is the server-side SQLSTATE evidence here.",
  "method": "Compare driver diagnostics and collector SQL state code, severity, message, HBA detail, and source location in both final summaries and raw records.",
  "position": 2,
  "runtime": [],
  "sources": [
    "doc.protocol.18",
    "runtime.28P01-registry-final-20260909.latest",
    "runtime.28P01-registry-final-20260909.pg10"
  ],
  "statement": "For the rejected startup connection, psycopg exposed startup text with sqlstate null while the PostgreSQL collector recorded FATAL SQLSTATE 28P01 and the password-failure message on both targets."
}
claims · runtime.authentication-repair
{
  "claim_id": "runtime.authentication-repair",
  "limits": "The run proves a password failure under the controlled md5 rule; it does not cover certificate, GSSAPI, PAM, LDAP, peer, or HBA syntax failures.",
  "method": "Use an owner connection to set the disposable role password, reload the temporary HBA rule, test wrong and known passwords through new connections, restore and reload the original rule, and assert a fresh owner probe.",
  "position": 3,
  "runtime": [],
  "sources": [
    "case-manifest.28P01",
    "snippet-registry.28P01.final",
    "runtime.28P01-registry-final-20260909.latest",
    "runtime.28P01-registry-final-20260909.pg10"
  ],
  "statement": "After enabling the temporary md5 rule, the known password opened a new role connection and returned SELECT 1 = 1; after exact HBA restoration, a fresh management connection also returned 1 on both targets."
}
claims · versions.catalogue-boundary
{
  "claim_id": "versions.catalogue-boundary",
  "limits": "The first scanned release is a lower bound, not an asserted introduction version.",
  "method": "Read the manifest snapshots and definition references for the code.",
  "position": 4,
  "runtime": [],
  "sources": [
    "manifest.28P01"
  ],
  "statement": "The locked catalogue records 28P01 in every listed formal snapshot from 9.0.23 through 18.6 and in 19beta3; pre-9.0 history is not scanned."
}
messages · message.password-failure
{
  "limits": "The fixed PG18.6 source passes logdetail through errdetail_log; a client ErrorResponse need not expose it. PG10 collector output uses a release-specific pg_hba.conf wording and may include an additional password-mismatch line.",
  "message_id": "message.password-failure",
  "path": "",
  "position": 0,
  "raw": {
    "detail_template": "Connection matched file \"%s\" line %d: \"%s\"",
    "detail_type": "collector log detail assembled at runtime",
    "id": "message.password-failure",
    "limits": "The fixed PG18.6 source passes logdetail through errdetail_log; a client ErrorResponse need not expose it. PG10 collector output uses a release-specific pg_hba.conf wording and may include an additional password-mismatch line.",
    "primary_template": "password authentication failed for user \"%s\"",
    "severity_source": "explicit FATAL",
    "sources": [
      "src.auth.18.6"
    ],
    "sqlstate": "28P01"
  },
  "severity": "explicit FATAL",
  "sources": [
    "src.auth.18.6"
  ],
  "templates": [
    {
      "kind": "primary",
      "literal": "password authentication failed for user \" \"",
      "position": 0,
      "role": "",
      "template": "password authentication failed for user \"%s\""
    },
    {
      "kind": "detail",
      "literal": "Connection matched file \" \" line : \" \"",
      "position": 1,
      "role": "",
      "template": "Connection matched file \"%s\" line %d: \"%s\""
    }
  ]
}
runtimes · runtime.28P01-registry-final-20260909.latest · 18.6 (Homebrew) · passed
{
  "cases": [
    "wrong_password_authentication"
  ],
  "limits": "",
  "position": 0,
  "raw": {
    "cases": [
      "wrong_password_authentication"
    ],
    "id": "runtime.28P01-registry-final-20260909.latest",
    "observed": {
      "collector_detail": "Connection matched file \"\u003cpg_hba.conf path\u003e\" line 1: \"host all all 0.0.0.0/0 md5\"",
      "collector_message": "password authentication failed for user \u003cgenerated-role\u003e",
      "collector_severity": "FATAL",
      "collector_source": "auth.c:320",
      "collector_sqlstate": "28P01",
      "driver_sqlstate": null,
      "driver_text": "FATAL: password authentication failed for user \u003cgenerated-role\u003e",
      "hba_reload": {
        "enabled": true,
        "restored": true
      },
      "known_password_probe": 1,
      "restored_management_probe": 1,
      "transaction": "none opened for rejected startup"
    },
    "raw": "verify/results/28P01-registry-final-20260909/latest/raw.jsonl",
    "raw_sha256": "97bcf605a806511aff3f0f4eeaa3615c159bf54e7d6f35b7bfbb45940d3d86d2",
    "run_id": "28P01-registry-final-20260909",
    "server_version": "18.6 (Homebrew)",
    "server_version_num": 180006,
    "snippet_registry": {
      "path": "verify/cases/28P01/snippets.json",
      "sha256": "9b2ca3d14cb093415043cb1cb8291eee2020df052f8067c4952ce2cd4597d395"
    },
    "status": "passed",
    "summary": "verify/results/28P01-registry-final-20260909/latest/summary.json",
    "summary_sha256": "0f58bf277fdd33be8d39ed8f05dc6de5555b8aa89db344b1a4cdfb3eb425bcbf",
    "target": "latest"
  },
  "run_id": "28P01-registry-final-20260909",
  "runtime_id": "runtime.28P01-registry-final-20260909.latest",
  "server_version": "18.6 (Homebrew)",
  "status": "passed",
  "target": "latest"
}
runtimes · runtime.28P01-registry-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
  "cases": [
    "wrong_password_authentication"
  ],
  "limits": "",
  "position": 1,
  "raw": {
    "cases": [
      "wrong_password_authentication"
    ],
    "id": "runtime.28P01-registry-final-20260909.pg10",
    "image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
    "observed": {
      "collector_detail": "Password does not match for user \u003cgenerated-role\u003e.\\nConnection matched pg_hba.conf line 1: \"host all all 0.0.0.0/0 md5\"",
      "collector_message": "password authentication failed for user \u003cgenerated-role\u003e",
      "collector_severity": "FATAL",
      "collector_source": "auth.c:329",
      "collector_sqlstate": "28P01",
      "driver_sqlstate": null,
      "driver_text": "FATAL: password authentication failed for user \u003cgenerated-role\u003e",
      "hba_reload": {
        "enabled": true,
        "restored": true
      },
      "known_password_probe": 1,
      "restored_management_probe": 1,
      "transaction": "none opened for rejected startup"
    },
    "raw": "verify/results/28P01-registry-final-20260909/pg10/raw.jsonl",
    "raw_sha256": "6d67921dfd66d347593d1b5c348cb60402eee0aa8dfc2cb9c2dbba7872caefb8",
    "run_id": "28P01-registry-final-20260909",
    "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
    "server_version_num": 100021,
    "snippet_registry": {
      "path": "verify/cases/28P01/snippets.json",
      "sha256": "9b2ca3d14cb093415043cb1cb8291eee2020df052f8067c4952ce2cd4597d395"
    },
    "status": "passed",
    "summary": "verify/results/28P01-registry-final-20260909/pg10/summary.json",
    "summary_sha256": "c8b82b3c42519fe121d27a815f224a25a12b8d14fdffd111dedd23f7a8a0a334",
    "target": "pg10"
  },
  "run_id": "28P01-registry-final-20260909",
  "runtime_id": "runtime.28P01-registry-final-20260909.pg10",
  "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
  "status": "passed",
  "target": "pg10"
}
sources · src.errcodes.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "",
  "location": "lines 271-278",
  "path": "src/backend/utils/errcodes.txt",
  "position": 0,
  "sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
  "source_id": "src.errcodes.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}
sources · src.auth.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "",
  "location": "lines 270-332",
  "path": "src/backend/libpq/auth.c",
  "position": 1,
  "sha256": "94252cb1e2c49b0ddb15f6596d0abf8056c84493de07cc81439da4c5b07018f1",
  "source_id": "src.auth.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/libpq/auth.c#L270-L332"
}
sources · doc.client-auth.18
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "",
  "location": "pg_hba.conf and password authentication",
  "path": "doc/src/sgml/client-auth.sgml",
  "position": 2,
  "sha256": "3fb31769e212f5ff97ffca769fe4c72c5963b90d0165bd6147f089e310167326",
  "source_id": "doc.client-auth.18",
  "tag": "PG18-docs",
  "url": "https://www.postgresql.org/docs/18/auth-pg-hba-conf.html"
}
sources · doc.protocol.18
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "",
  "location": "ErrorResponse fields",
  "path": "doc/src/sgml/protocol.sgml",
  "position": 3,
  "sha256": "745339e07ebbc2bb67d98b258e25772ada644ef26011e3cd6b3fcbb435235f89",
  "source_id": "doc.protocol.18",
  "tag": "PG18-docs",
  "url": "https://www.postgresql.org/docs/18/protocol-error-fields.html"
}
sources · manifest.28P01
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "snapshots and definition_blobs entries for the 28P01 definition",
  "path": "sources/manifest.lock.json",
  "position": 4,
  "sha256": "1727a275f336988ff96b4f9990a4ca253080f73fc5d316e7def165c8cf3708a8",
  "source_id": "manifest.28P01",
  "tag": "",
  "url": "../sources/manifest.lock.json"
}
sources · case-manifest.28P01
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "wrong_password_authentication",
  "path": "verify/cases/28P01/cases.json",
  "position": 5,
  "sha256": "f6b0cfcd0752036c7d3368586fb86740b5ef9364da20800554be02e89d44149f",
  "source_id": "case-manifest.28P01",
  "tag": "",
  "url": "../verify/cases/28P01/cases.json"
}
sources · snippet-registry.28P01.final
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "wrong_password_authentication ordered SQL",
  "path": "verify/cases/28P01/snippets.json",
  "position": 6,
  "sha256": "9b2ca3d14cb093415043cb1cb8291eee2020df052f8067c4952ce2cd4597d395",
  "source_id": "snippet-registry.28P01.final",
  "tag": "",
  "url": "../verify/cases/28P01/snippets.json"
}

来源引用

完整定义与证据 JSON

定义来源

center · PostgreSQL 18 · english-manuals:890476e06c67c07baa2c0404c5accab30fc55ff21e0e5f0cf28d7af62891e504

正文语言: zh-Hans · english-manuals:890476e06c67c07baa2c0404c5accab30fc55ff21e0e5f0cf28d7af62891e504