如果有活动连接,如何删除PostgreSQL数据库?

How to drop a PostgreSQL database if there are active connections to it?

我需要编写一个脚本来删除PostgreSQL数据库。可能有很多连接到它,但是脚本应该忽略这一点。

当存在打开的连接时,标准的DROP DATABASE db_name查询不起作用。

我怎样才能解决这个问题?


这将删除除您的以外的现有连接:

查询pg_stat_activity并获取要杀死的PID值,然后向它们发出SELECT pg_terminate_backend(pid int)

PostgreSQL 9.2及以上版本:

1
2
3
4
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND pid <> pg_backend_pid();

PostgreSQL 9.1及以下:

1
2
3
4
SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND procpid <> pg_backend_pid();

一旦断开所有人的连接,您就必须断开连接并从另一个数据库发出drop database命令,也就是说,不是您要删除的数据库。

注意将procpid列重命名为pid。查看此邮件列表线程。


在PostgreSQL 9.2及更高版本中,要断开除会话之外的所有与所连接数据库的连接,请执行以下操作:

1
2
3
4
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
  AND pid <> pg_backend_pid();

在旧版本中是一样的,只需将pid更改为procpid。要断开与其他数据库的连接,只需将current_database()更改为要断开用户连接的数据库的名称。

在断开用户连接之前,您可能希望从数据库的用户那里获得REVOKECONNECT的权利,否则用户将继续重新连接,您将永远没有机会删除数据库。请参阅此注释及其关联的问题,如何从数据库中分离所有其他用户。

如果只想断开空闲用户的连接,请参见此问题。


在使用pg_terminate_backend(int)函数删除数据库之前,可以终止所有连接。

您可以使用系统视图pg_stat_activity获取所有正在运行的后端。

我不完全确定,但以下可能会扼杀所有会话:

1
2
3
SELECT pg_terminate_backend(procpid)
FROM pg_stat_activity
WHERE datname = 'doomed_database'

当然,您可能无法连接到该数据库


我注意到Postgres9.2现在调用的是列pid而不是procpid。

我倾向于从外壳来称呼它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env bash
# KILL ALL connections TO the postgres server
IF [ -n"$1" ] ; THEN
  WHERE="where pg_stat_activity.datname = '$1'"
  echo"killing all connections to database '$1'"
ELSE
  echo"killing all connections to database"
fi

cat <<-EOF | psql -U postgres -d postgres
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
${WHERE}
EOF

希望有帮助。感谢@justbob提供的SQL。


根据您的PostgreSQL版本的不同,您可能会遇到一个bug,这使得pg_stat_activity忽略掉掉掉的用户的活动连接。这些连接也不会显示在pgadminiii中。

如果您正在进行自动测试(其中还创建了用户),这可能是一个可能的场景。

在这种情况下,您需要恢复到如下查询:

1
2
3
 SELECT pg_terminate_backend(procpid)
 FROM pg_stat_get_activity(NULL::INTEGER)
 WHERE datid=(SELECT oid FROM pg_database WHERE datname = 'your_database');

注:在9.2+中,您将把procpid改为pid


在Linux命令提示符中,我将首先通过绑定此命令停止所有正在运行的PostgreSQL进程。sudo/etc/init.d/postgresql重启

键入命令bg检查其他PostgreSQL进程是否仍在运行

然后跟随dropdb dbname删除数据库

1
2
3
sudo /etc/init.d/postgresql restart
bg
dropdb dbname

这对我在Linux命令提示符下有效


我只是重新启动Ubuntu中的服务来断开连接的客户机。

1
2
3
4
5
sudo service postgresql stop
sudo service postgresql START

psql
DROP DATABASE DB_NAME;

PostgreSQL 9.2及以上版本:

SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'


这是我的黑客…= D

1
2
3
4
5
6
7
8
# Make sure no one can CONNECT TO this DATABASE EXCEPT you!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c"UPDATE pg_database SET datallowconn=false WHERE datname='<DATABASE_NAME>';"

# DROP ALL existing connections EXCEPT FOR yours!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c"SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '<DATABASE_NAME>' AND pid <> pg_backend_pid();"

# DROP DATABASE! =D
sudo -u postgres /usr/pgsql-9.4/bin/psql -c"DROP DATABASE <DATABASE_NAME>;"

我之所以给出这个答案,是因为包含了一个命令(在上面)来阻止新的连接,并且因为任何使用该命令的尝试…

1
REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;

…不要阻止新连接!

感谢@araqnid@goatwalker!= D

https://stackoverflow.com/a/3185413/3223785


在我的例子中,我必须执行一个命令来删除所有连接,包括我的活动管理员连接。

1
2
3
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()

它终止了所有连接并向我显示致命的"错误"消息:

FATAL: terminating connection due to administrator command SQL state: 57P01

之后就可以删除数据库了