HOWTO · PostgreSQL

终止 PostgreSQL 连接

本文介绍如何终止在 PostgreSQL 中打开的连接。

本页内容

要结束一个 PostgreSQL 连接,先在 pg_stat_activity 中找到它对应的后端进程,再针对该会话调用 pg_terminate_backend(pid)。如果只需停止当前查询并保留连接,请改用 pg_cancel_backend(pid)。日常管理会话时,避免直接终止操作系统进程,因为这会绕过 PostgreSQL 的会话控制,并可能影响服务器稳定性。

检查会话并选择目标

在数据库服务器上运行查询,检查活动和空闲会话。pid 标识后端进程,datname 标识数据库,usename 标识角色,application_name 可帮助识别客户端,而 state 表示会话处于活动还是空闲状态。判断某个会话是否适合停止时,也要查看 query 和 state_change。查询文本本身也可能受到访问限制。

使用 pg_backend_pid() 找出运行检查查询的会话。将该 PID 排除,以免命令终止自身连接。按数据库缩小目标范围;必要时也可按角色或应用程序筛选。终止生产环境中的会话前,先确认会话所有者及预期影响;终止会话会回滚其中正在进行的事务。

例如,可用以下 SQL 表达式检查候选会话(请替换数据库名称,并根据环境添加适当筛选条件):SELECT pid, usename, application_name, state, query FROM pg_stat_activity WHERE datname = 'my_database' AND pid <> pg_backend_pid();。这条查询只用于筛选,不会结束任何会话。

这段 Python 示例使用示例会话记录并打印 [4101],不会连接到 PostgreSQL。

本节中的代码以及显示的标签或输出仍为英文。

sessions = [
    {"pid": 4101, "database": "shop", "state": "idle"},
    {"pid": 4102, "database": "shop", "state": "active"},
    {"pid": 4103, "database": "reports", "state": "idle"},
]
current_pid = 4102
target_database = "shop"
targets = [
    session["pid"]
    for session in sessions
    if session["database"] == target_database
    and session["pid"] != current_pid
]
print(targets)
[4101]

取消查询或终止会话

pg_cancel_backend(pid) 会请求取消当前查询。后端仍保持连接,之后可以运行其他查询。当问题出在查询本身、但客户端会话仍需继续使用时,适合采用这种方式。

pg_terminate_backend(pid) 会结束指定的后端会话。客户端会断开连接,未完成的事务也会回滚。当必须结束连接本身时,例如清理占用资源的闲置会话,可以使用它。取消请求可能不会立即停止工作;如果客户端软件配置为自动重连,终止会话后它也可能重新连接。

使用 PostgreSQL 函数安全地终止指定会话

先运行只读查询检查候选会话,例如:SELECT pid, usename, application_name, state, query FROM pg_stat_activity WHERE datname = 'my_database' AND pid <> pg_backend_pid();。确认每个目标会话的所有者和影响后,将一个已核实的 PID 传给 pg_terminate_backend,例如 SELECT pg_terminate_backend(4101);(将 4101 替换为你确认的 PID)。这条语句会立即生效:PostgreSQL 会向该后端发送信号、断开其客户端,并回滚尚未提交的事务。其布尔返回值表示 PostgreSQL 是否接受了该信号;之后可再次检查 pg_stat_activity,确认该后端是否已消失。若要处理多个会话,先检查完整的目标集合,再逐个终止已确认的 PID,或使用目标范围明确且已逐一核实的条件。

检查权限和版本差异

能否向其他后端发送信号,取决于 PostgreSQL 的版本和已授予的权限。超级用户可以执行此操作;在提供相关功能的版本中,PostgreSQL 也支持指定的信号发送权限。不要假定所有安装都必须使用超级用户权限,也不要认为普通角色都能终止任意会话。请查阅对应服务器版本的文档,并确认授予你角色的权限。

pg_backend_pid() 会返回当前会话的 PID,适合用于排除自身。较早版本的系统视图使用过不同的列名;除非确认目标服务器版本提供了 procpid 这样的旧标识符,否则不要将其替换到查询中。

验证结果并排查常见故障

调用 pg_terminate_backend 后,使用相同的目标筛选条件再次查询 pg_stat_activity。如果 PID 已不存在,说明该后端已结束。如果函数返回 false 或该行仍然存在,请检查 PID 是否仍有效、你是否有权向其发送信号,以及目标是否已经开始退出。客户端可能会使用不同的 PID 建立新连接,因此要区分客户端重新连接与原后端仍在运行这两种情况。

权限错误通常与角色权限或服务器版本规则有关。即使信号发送成功,也可能需要稍等片刻才能观察到结果;函数的布尔值表示信号处理情况,并不代表应用程序层面的恢复已经完成。排查影响时,请检查应用程序日志和事务结果。

避免直接终止 PostgreSQL 进程

ps 等工具可帮助管理员检查操作系统进程,但仅凭进程名称匹配,无法安全地确定要终止哪个数据库会话。不要把 kill 或 kill -9 当作断开客户端连接的常规方法。直接向进程发送信号会绕过 PostgreSQL 的正常会话管理,并可能中断服务器工作;强制信号还可能造成更广泛的恢复问题。管理单个会话时,请使用 PostgreSQL 的信号发送函数。

何时适合重启服务器

只有在服务器本身需要维护或恢复,并且你了解所有已连接客户端都可能断开时,才重启 PostgreSQL 服务。重启的影响远大于结束单个后端。具体命令取决于 PostgreSQL 的安装和管理方式:使用该主机配置的服务管理器或集群管理工具,并在操作前确认实例和数据目录无误。Homebrew 服务命令和 pg_ctl 仅适用于相应的安装方式,不能视为通用且可互换的命令。若只需处理单个不需要的连接,请改为从 PostgreSQL 检查并向其后端发送信号。