PostgreSQL-由于与数据库的某些自动连接而无法删除数据库


161

每当我尝试删除数据库时,我都会得到:

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';

我终止了与该数据库的连接,但是如果在此之后尝试删除数据库,则有人会自动连接到该数据库并给出此错误。该怎么办?除了我之外,没有人使用这个数据库。

Answers:


193

您可以防止以后的连接:

REVOKE CONNECT ON DATABASE thedb FROM public;

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

然后,您可以终止与该数据库的所有连接,但您自己的连接除外:

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;

19
如果以后导入另一个具有相同名称的数据库,则将连接功能授予public back:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin

154

每当我尝试删除数据库时,我都会得到:

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';

它肯定会工作。


5
这为我做到了。谢谢
rpivovar

发现!谢谢!🎉
slajma

做得完美。谢谢。
Mustafa Magdi

34

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

ps -ef | grep postgres

通过此命令终止进程

sudo kill -9 PID

不,它太硬了,如果因为有其他正在访问的数据库而无法进行pg处理,该怎么办?
弗拉基米尔·斯塔吉洛夫

2
@VladimirStazhilov将显示数据库名称和该数据库的pid。有人可以选择特定的pid仅杀死该特定数据库。
Dinesh Pallapa

29

只需检查什么是连接,它是从哪里来的。您可以在以下位置看到所有这些:

select * from pg_stat_activity where datname = 'TARGET_DB';

也许是您的联系?


4
在看到结果后在终端中sudo kill -9 PID
Dan Rey Oquindo 2015年

25

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

root@kalilinux:~#sudo service postgresql restart

然后尝试删除数据库:

postgres=# drop database test_database;

这将达到目的。


11

使用UI的pgAdmin 4解决方案

如果没有,请首先在仪表板上启用显示活动:

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

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

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

现在应该可以删除数据库了。


效果很好-我用PgAdmin 4.5和PostgreSQL 11.2(由Visual C ++ build 1914,64位(Windows)编译)进行了测试。
vab2048 '19

2
我认为这是最好的解决方案。这真的很好!
Lahiru


8

解决方案:
1.关闭Pg服务器 2.它将断开所有活动的连接 3.重新启动Pg服务器 4.尝试您的命令
在此处输入图片说明




Mac上的Postgress.app也对我有用。在这种情况下,您将停止/启动服务器
JuanJoséRamírez


3

就我而言,我正在使用AWS Redshift(基于Postgres)。看来没有其他连接到数据库,但是我遇到了同样的错误。

ERROR:  database "XYZ" is being accessed by other users

就我而言,似乎数据库集群仍在对数据库进行某些处理,并且尽管没有其他外部/用户连接,但数据库仍在内部使用。我通过运行以下命令找到了它:

SELECT * FROM stv_sessions;

因此,我的技巧是在代码中编写一个循环,以查找其中包含我的数据库名称的行。(当然,循环不是无限的,而是一个困循环,等等)

SELECT * FROM stv_sessions where db_name = 'XYZ';

如果找到行,请继续删除每个PID。

SELECT pg_terminate_backend(PUT_PID_HERE);

如果找不到行,请继续删除数据库

DROP DATABASE XYZ;

注意:就我而言,我正在编写Java单元/系统测试,在这里可以认为这是可以接受的。这对于生产代码是不可接受的。


这是Java中的完整技巧(忽略我的测试/实用程序类)。

  int i = 0;
  while (i < 10) {
    try {
      i++;
      logStandardOut("First try to delete session PIDs, before dropping the DB");
      String getSessionPIDs = String.format("SELECT stv_sessions.process, stv_sessions.* FROM stv_sessions where db_name = '%s'", dbNameToReset);
      ResultSet resultSet = databaseConnection.execQuery(getSessionPIDs);
      while (resultSet.next()) {
        int sessionPID = resultSet.getInt(1);
        logStandardOut("killPID: %s", sessionPID);
        String killSessionPID = String.format("select pg_terminate_backend(%s)", sessionPID);
        try {
          databaseConnection.execQuery(killSessionPID);
        } catch (DatabaseException dbEx) {
          //This is most commonly when a session PID is transient, where it ended between my query and kill lines
          logStandardOut("Ignore it, you did your best: %s, %s", dbEx.getMessage(), dbEx.getCause());
        }
      }

      //Drop the DB now
      String dropDbSQL = String.format("DROP DATABASE %s", dbNameToReset);
      logStandardOut(dropDbSQL);
      databaseConnection.execStatement(dropDbSQL);
      break;
    } catch (MissingDatabaseException ex) {
      //ignore, if the DB was not there (to be dropped)
      logStandardOut(ex.getMessage());
      break;
    } catch (Exception ex) {
      logStandardOut("Something went wrong, sleeping for a bit: %s, %s", ex.getMessage(), ex.getCause());
      sleepMilliSec(1000);
    }
  }

2

我认为在后台运行着一些空闲查询。

  1. 尝试先显示正在运行的查询
SELECT pid, age(clock_timestamp(), query_start), usename, query 
FROM pg_stat_activity 
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' 
ORDER BY query_start desc;
  1. 杀死空闲查询(检查它们是否正在引用有问题的数据库,或者可以从选择结果中使用pid杀死所有数据库或杀死特定数据库)

选择pg_terminate_backend(procpid);

注意:终止选择查询不会造成任何不良影响


2

REVOKE CONNECT不会阻止数据库所有者或超级用户的连接。因此,如果您不希望任何人连接数据库,那么遵循命令可能很有用。

alter database pilot allow_connections = off;

然后使用:

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

1
谢谢...在我的情况下REVOKE CONNECT还不够。
6

1

虽然我发现在其他场合也可以使用上面两个最高的答案,但是今天,解决此问题的最简单方法是意识到PyCharm可能会保持会话开放,如果我单击StopPyCharm,那可能会有所帮助。在浏览器中打开pgAdmin4时,我这样做了,几乎立即看到Database session stats降至0,这时我就可以删除数据库了。


“ PyCharm可能会保持会话开放”?怎么样?我在PyCharm的终端(带有peewee的前端Python,后端Postgres)中运行单元测试,即“停止”按钮显示为灰色,但是我仍然保留这些错误……
Laryx Decidua

@LaryxDecidua我认为,就我而言,我必须在使用数据库的PyCharm中运行一个服务实例。如果退出PyCharm,实例数是否会降至0,从而允许您删除数据库?如果是这样,则必须仍然有某些内容(数据库资源管理器,SQL查询等)保持连接。
hlongmore

1

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

brew services restart postgresql

-1

在终端中,请尝试以下命令:

ps -ef | grep postgres

您将看到:

501 1445 3645 0 12:05 AM 0:00.03 postgres:sasha dbname [local]空闲

第三个数字(3645)是PID。

您可以删除

sudo kill -9 3645

然后,启动您的PostgreSQL连接。

手动启动:

pg_ctl -D /usr/local/var/postgres start
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.