PostgreSQL-由于一些自动连接到数据库,无法删除数据库

307

每当我尝试删除数据库时,都会出现以下错误:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

当我使用:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

我从那个数据库中断了连接,但是如果我在此之后尝试删除数据库,某种方式有人会自动连接到该数据库并出现错误。可能是什么原因导致这样?除我之外没有人使用这个数据库。

25个回答

335

Postgres 13+

使用 WITH (force)

请参考 https://dev59.com/KmQm5IYBdhLWcg3wowWw#68982312

Postgres 12及以下版本

您可以使用以下方法阻止未来的连接:

REVOKE CONNECT ON DATABASE thedb FROM public;

(以及可能的其他用户/角色; 请参见 psql 中的\l+

然后,您可以终止除自己之外的所有连接到此数据库:

SELECT pid, pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = current_database() AND pid <> pg_backend_pid();

在旧版本中,pid 被称为 procpid,所以你需要处理一下。

由于您已经撤销了 CONNECT 权限,任何试图自动连接的操作都将无法执行。

现在您可以删除数据库了。

如果您正在使用超级用户连接进行正常操作,则此方法不适用。但是如果您正在这样做,您需要先解决这个问题。


在删除数据库后,如果您重新创建数据库,可以执行以下命令来恢复访问权限。

GRANT CONNECT ON DATABASE thedb TO public;

24
如果您稍后导入具有相同名称的另一个数据库,请将连接能力授予公共用户:GRANT CONNECT ON DATABASE thedb TO public; - Mikhail Vasin
4
REVOKE CONNECT 不会阻止数据库所有者或超级用户的连接。因此,如果您不希望任何人连接到数据库,请执行命令 alter database pilot allow_connections = off - inferno
4
这是一种实现此操作的方式,但使用带有“FORCE”的Postgresql 13更新可以大大简化此过程。请查看我的答案手册 - Renis1235
current_database() 对我不起作用,但这个没问题(db_name 在单引号中):SELECT pid, pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'db_name' AND pid <> pg_backend_pid(); - alboforlizo
1
从Postgres 13开始,使用WITH (FORCE)有一个更简单的方法:https://dev59.com/KmQm5IYBdhLWcg3wowWw#68982312 - degenerate

252

每当我尝试删除数据库时,我会得到以下提示:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

首先,您需要撤销

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

然后使用:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

肯定会有效。


4
根据使用数据库的会话数量,最终的SQL语句可能需要多次运行。总体来说,这种方法表现良好。 - Zeeng
在docker-compose下,如果您使用db dbname,这并没有帮助,因为psql似乎连接到了数据库,所以您仍然无法删除。我不确定。 - Eugene Gr. Philippov

65

Postgresql 13 更新

你可以使用以下命令来强制删除一个数据库,从而断开与其连接的每个用户/应用程序。

DROP DATABASE db_name WITH (FORCE)

你可以查看更多的手册
FORCE - 试图终止与目标数据库的所有现有连接。如果目标数据库中存在已准备好的事务、活动的逻辑复制插槽或订阅,则不会终止。
附注:在执行此查询时,您不能删除正在连接的数据库。

2
只要在运行时连接到不同的数据库,这将非常有效。否则,您将收到一个错误,指出您无法删除当前连接的数据库。 - degenerate
这是最棒的! - undefined

52

我找到了解决这个问题的方法,请尝试在终端中运行此命令。

ps -ef | grep postgres

使用此命令终止进程

sudo kill -9 PID

1
不行,这太硬编码了,如果你有其他正在被访问的数据库,你怎么能杀掉pg进程呢? - Vladimir Stazhilov
2
@VladimirStazhilov 这将显示数据库名称和该数据库的pid。某人可以选择特定的pid仅杀死该特定的数据库。 - Dinesh Pallapa
1
ps -ef | grep postgres | grep YourAppName | cut -w -f3 | xargs kill -9 - dezman

51

这意味着另一个用户正在访问数据库。只需重新启动PostgreSQL即可解决问题。使用以下命令:

root@kalilinux:~#sudo service postgresql restart

然后尝试删除数据库:

postgres=# drop database test_database;

这样就可以了。


1
非常感谢,这对我很有帮助。我想要补充一点,如果数据库名称中有连字符“-”,请用引号括起来,例如:"my-database"。 - destroyer22719
2
这是一个伟大而简单的解决方案! - David Alford
1
如果在开发环境中使用,这将是很好的选择。在这种情况下,它正是你所需要的。然而,就生产脚本而言,可能会有其他需要考虑的因素,正如上面的解决方案所指出的那样。 - Harlin

45

只需检查连接及其来源。您可以在以下位置查看所有内容:

SELECT * FROM pg_stat_activity WHERE datname = 'TARGET_DB';

也许是您的连接问题?

6
在看到结果后,在终端中输入“sudo kill -9 PID”来强制结束进程。 - Dan Rey Oquindo

30

使用pgAdmin 4的图形用户界面解决方案。

如果您还没有开启仪表盘上的显示活动,请先开启:

File > Preferences > Dashboards > Display > Show Activity > true

现在禁用所有使用db的进程:

  1. 点击DB名称
  2. 点击仪表板>会话
  3. 点击刷新图标
  4. 点击每个进程旁边的删除(x)图标以结束它们

现在您应该能够删除数据库。


这个很好用 - 我用PgAdmin 4.5和PostgreSQL 11.2测试过,由Visual C++ build 1914编译,64位(Windows)。 - vab2048
2
这是我认为最好的解决方案。它真的很有效! - Lahiru Jayaratne
2
要查看“仪表板”,请右键单击顶部菜单,然后选择“添加面板-> 仪表板”。 - kkuilla

15
如果不会影响到您机器上的其他服务,只需运行service postgresql restart即可。

12

解决方案:
1. 关闭Pg服务器
这里输入图片描述
2. 这将断开所有活动连接
3. 重新启动Pg服务器
4. 尝试您的命令


这对我也适用,我在Mac上使用Postgress.app。在那种情况下,您需要停止/启动服务器。 - Juan José Ramírez

12
在macOS中,通过控制台使用以下命令尝试重新启动postgresql数据库:
brew services restart postgresql

是的,我使用postgres.app,重新启动服务器解决了问题。 - Pencilcheck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接