跳转到主要内容

25P03 — 事务中空闲会话超时(idle_in_transaction_session_timeout)

PostgreSQL SQLSTATE 25P03:诊断并恢复开放事务中空闲会话被服务器终止的过程。

25P03 — 事务中空闲会话超时(idle_in_transaction_session_timeout)

速览

25P03 是终止会话的 FATAL 条件。当会话在开放事务中等待客户端下一条查询的时间超过有效 idle_in_transaction_session_timeout 时触发。选定案例使用 300 ms 作为测试触发值,不是生产建议。

字段
SQLSTATE 25P03
条件名 idle_in_transaction_session_timeout
状态 有效
已知存在于 9.6.0
锁定快照 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3
ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT
别名

含义

该超时防止会话在等待客户端期间长期持有开放事务,从而持有锁并延迟清理。它作用于事务中的空闲等待,包括 idle in transactionidle in transaction (aborted) 状态,不是正在执行的语句;statement_timeout 取消单条语句,而支持该设置的版本中 transaction_timeout 限制整个事务生命周期。选定运行只覆盖未中止的 INTRANS 路径。

诊断

会话消失前,先在该目标会话自身检查有效的 SHOW idle_in_transaction_session_timeout(或对应的 pg_settings 行)。控制连接上的 SHOWpg_settings 反映的是观察者后端,不能用来确认另一个会话实际通过 SET 得到的值。再从控制连接查看 pg_stat_activitypidusenameapplication_nameclient_addrstatexact_startstate_changequery_startquery 等字段,并筛选 state IN ('idle in transaction', 'idle in transaction (aborted)')。若状态已经中止,应把更早的根错误和 25P02 作为独立诊断保留;选定运行是未中止的 INTRANS 路径。这些字段可定位连接池或应用路径以及空闲时长,但观察者权限可能限制可见内容。再按 backend PID、SQLSTATE、error_severity = FATAL 和精确报文关联 FATAL 记录。选定的 psycopg/libpq 栈在驱动诊断和 CSV 日志中都暴露了 25P03;PG18 还提供 JSON 日志。原连接已关闭,不能在其上用 ROLLBACK 修复事务。

处理

把原会话视为已消失:从连接池移除它,重连后再判断能否重试幂等工作。要避免再次发生,应在连接归还连接池前提交或回滚,并修复留下开放事务的应用路径。不要为了压制错误而降低该超时;更短的值会更容易触发终止。可把有效值设在合法空闲时长之上;只有部署明确接受锁和清理风险时才设为 0。服务器关闭该会话时会在退出前回滚开放且尚未完成的事务;死亡连接不能再接收 ROLLBACK。对已终止会话中已知未提交的事务,不能通过该连接恢复。若是另一种网络故障发生在客户端可能已发送 COMMIT 之后,应从新连接对账业务结果再重试;并非每个 25P03 FATAL 都意味着这种不确定性。

FATAL 报文

服务器源码固定报出 terminating connection due to idle-in-transaction timeout,严重级别为 FATAL;原连接会被终止。

实测诊断

18.6 (Homebrew) / latest:FATAL SQLSTATE 25P03;主报文 terminating connection due to idle-in-transaction timeout;backend PID 26447;原连接已关闭 True;CSV 日志 25P03;JSON 日志 25P03;新连接探测 110.21 (Debian 10.21-1.pgdg90+1) / pg10:FATAL SQLSTATE 25P03;主报文 terminating connection due to idle-in-transaction timeout;backend PID 81;原连接已关闭 True;CSV 日志 25P03;JSON 日志 不适用;新连接探测 1

代表案例

下列 SQL 片段不是一次性粘贴脚本:在测试连接上执行设置、PID 和 BEGIN 后停止发送查询,由独立观察连接或日志收集器等待 FATAL;原连接终止后,另开新连接执行最后的探测。运行器从共享语句清单(registry)读取这些语句,完整断言、日志收集器关联、环境和清理见 案例导出

-- set_timeout
SET idle_in_transaction_session_timeout = '300ms';
-- backend_pid
SELECT pg_backend_pid();
-- begin
BEGIN;
-- probe
SELECT 1;

上述片段的 SQLSTATE、诊断、状态和修复断言来自共享语句清单(registry)(SHA-256 95fd079c8bca77c6e3ffc398e404a218e4f810e5fa36e30127cbc6470a6d6eb2);结构化证据

作者证据 ID:identity, timeout-path, runtime。选定运行记录:runtime.25P03-batch2c-latest-20260909.latest, runtime.25P03-batch2c-pg10-20260909.pg10

版本与边界

选定的 300 ms 终止案例在 PostgreSQL 18.6 与 10.21 通过。PG18 按配置提供 CSV 和 JSON 日志记录;PG10 只有 CSV。两个目标的新连接都成功执行 SELECT 1。超时值取决于部署,本案例不规定生产值。

25P04 事务超时25006 只读 SQL 事务57014 查询取消

来源