PostgreSQL pg_terminate_backend() 函数用法与实例
在 PostgreSQL 运维与高并发业务场景中,我们经常会遇到长事务阻塞、查询慢死锁、或是执行 DROP DATABASE / ALTER DATABASE RENAME 时因存在活动连接而报错的情况。
pg_terminate_backend() 是 PostgreSQL 提供的核心系统管理函数,用于向指定的后台会话进程发送终止信号(SIGTERM),强制断开客户端连接并释放其持有的所有锁和资源。
语法
pg_terminate_backend() 函数的调用签名如下:
pg_terminate_backend(pid integer, timeout bigint DEFAULT 0) -> boolean
参数
pid- 必需。要终止的后台进程标识符(Process ID,整数类型),通常从系统视图
pg_stat_activity的pid列获取。 timeout- 可选(PostgreSQL 14+ 引入)。等待进程实际终止的超时毫秒数,默认值为
0。- 当为
0时,函数在向操作系统进程发送终止信号后立即返回true,不阻塞等待; - 当大于
0时,函数将持续等待进程完全退出,直到指定毫秒数;如果在超时前成功退出返回true,超时仍未退出则返回false。
- 当为
返回值
- 返回
true:表示终止信号发送成功(或在指定超时时间内进程成功退出); - 返回
false:表示目标 PID 不存在、超时未退出或当前用户无权终止该进程。
权限要求
- 超级用户(Superuser) 或具有
pg_signal_backend预定义角色的用户可以终止任意用户的后台连接; - 普通用户 仅允许终止属于其自身角色的连接,尝试终止其他用户的进程将返回
false并记录权限警告。
与 pg_cancel_backend() 的区别
PostgreSQL 提供了两个会话控制函数,很多开发者容易混淆:
| 特性 | pg_cancel_backend(pid) |
pg_terminate_backend(pid) |
|---|---|---|
| 底层信号 | 发送 SIGINT 信号 |
发送 SIGTERM 信号 |
| 动作影响 | 仅取消该连接当前正在执行的一条 SQL 查询 | 彻底销毁整个连接会话,客户端直接掉线 |
| 客户端状态 | 连接依然保持,可继续执行后续查询 | 客户端抛出连接断开错误(如 connection closed) |
| 适用场景 | 终止单条卡住的超长慢查询,不影响客户端应用连接池 | 强制清理无响应进程、死锁、准备删除数据库清空连接 |
实战示例
查询当前所有活动连接与 PID
在终止进程前,必须先通过 pg_stat_activity 找到目标连接的 pid、状态及正在执行的 SQL:
SELECT
pid,
usename,
datname,
client_addr,
state,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
ORDER BY duration DESC;
[!TIP]
WHERE pid <> pg_backend_pid()用于排除当前正在执行查询的自身连接,避免误杀当前会话。
示例 1:终止单个指定的连接进程
假设发现 pid = 41285 的会话处于异常挂起状态,直接终止:
SELECT pg_terminate_backend(41285);
输出:
pg_terminate_backend
----------------------
t
(1 row)输出 t(true)表示信号成功发送,目标连接已断开。
示例 2:删除数据库前清空目标库的所有活动连接
在执行 DROP DATABASE testdb; 时,若有任何客户端连接到 testdb,PostgreSQL 会报 ERROR: database "testdb" is being accessed by other users。
可以使用如下语句批量强杀该数据库的所有非自身连接:
SELECT
pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'testdb'
AND pid <> pg_backend_pid();
执行后即可顺利执行 DROP DATABASE testdb;。
示例 3:批量清理空闲过久的事务连接(idle in transaction)
在业务系统中,“开启事务后未提交亦未回滚”的连接(idle in transaction)会长时间阻止表上的元数据锁释放或导致 VACUUM 无法清理死元组。
以下 SQL 可安全清理事务开启超过 10 分钟的僵尸连接:
SELECT
pid,
usename,
now() - state_change AS idle_duration,
pg_terminate_backend(pid) AS terminated
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND state_change < now() - INTERVAL '10 minutes';
结论
pg_terminate_backend() 是 PostgreSQL 数据库管理员手中强有力的运维工具。在遇到业务死锁、高危全表扫描卡死、或需要释放目标库连接时,配合 pg_stat_activity 过滤条件,能够精准高效地恢复数据库健康状态。在日常使用中,建议先尝试温和的 pg_cancel_backend(),无效时再使用 pg_terminate_backend()。