Postgresql - Datenbank kann aufgrund einiger automatischer Verbindungen zur Datenbank nicht gelöscht werden

160

Immer wenn ich versuche, die Datenbank zu löschen, erhalte ich:

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

Wenn ich benutze:

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

Ich habe die Verbindung von dieser Datenbank beendet, aber wenn ich danach versuche, die Datenbank zu löschen, stellt jemand automatisch eine Verbindung zu dieser Datenbank her und gibt diesen Fehler aus. Was könnte das tun? Niemand außer mir benutzt diese Datenbank.

Andrius
quelle

Antworten:

192

Sie können zukünftige Verbindungen verhindern:

REVOKE CONNECT ON DATABASE thedb FROM public;

(und möglicherweise andere Benutzer / Rollen; siehe \l+inpsql )

Sie können dann alle Verbindungen zu dieser Datenbank mit Ausnahme Ihrer eigenen beenden:

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

Bei älteren Versionen pidwurde aufgerufen, procpidalso müssen Sie sich darum kümmern.

Da Sie CONNECTRechte widerrufen haben, sollte alles, was versucht hat, eine automatische Verbindung herzustellen, dies nicht mehr können.

Sie können jetzt die Datenbank löschen.

Dies funktioniert nicht, wenn Sie Superuser-Verbindungen für den normalen Betrieb verwenden. Wenn Sie dies jedoch tun, müssen Sie das Problem zuerst beheben.

Craig Ringer
quelle
19
Wenn Sie später eine andere Datenbank mit demselben Namen importieren, gewähren Sie public back die Verbindungsfunktion: GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin
153

Immer wenn ich versuche, die Datenbank zu löschen, erhalte ich:

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

Zuerst müssen Sie widerrufen

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Dann benutze:

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

Es wird sicherlich funktionieren.

Suneel Kumar
quelle
5
Das hat es für mich getan. Danke
rpivovar
Genau richtig! Danke dir! 🎉
Slajma
Hat perfekt funktioniert. Danke dir.
Mustafa Magdi
34

Ich habe eine Lösung für dieses Problem gefunden. Versuchen Sie, diesen Befehl im Terminal auszuführen

ps -ef | grep postgres

Prozess mit diesem Befehl beenden

sudo kill -9 PID
Dinesh Pallapa
quelle
Nein, es ist zu hardcode. Was ist, wenn Sie den pg-Prozess nicht beenden können, weil auf andere Datenbanken zugegriffen wird?
Vladimir Stazhilov
2
@VladimirStazhilov Hier werden der Datenbankname und die PID dieser Datenbank angezeigt. Jemand kann nur diese bestimmte Datenbank auswählen.
Dinesh Pallapa
29

Überprüfen Sie einfach, welche Verbindung besteht und woher sie kommt. Sie können dies alles sehen in:

select * from pg_stat_activity where datname = 'TARGET_DB';

Vielleicht ist es deine Verbindung?


quelle
4
sudo kill -9 PID im Terminal nach dem Ergebnis
Dan Rey Oquindo
24

Dies bedeutet, dass ein anderer Benutzer auf die Datenbank zugreift. Starten Sie PostgreSQL einfach neu. Dieser Befehl erledigt den Trick

root@kalilinux:~#sudo service postgresql restart

Versuchen Sie dann, die Datenbank zu löschen:

postgres=# drop database test_database;

Dies wird den Trick machen.

Suman Astani
quelle
11

pgAdmin 4- Lösung mit Benutzeroberfläche

Aktivieren Sie zuerst die Showaktivität im Dashboard, wenn Sie Folgendes nicht getan haben:

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

Deaktivieren Sie nun alle Prozesse mit der Datenbank:

  1. Klicken Sie auf den DB-Namen
  2. Klicken Sie auf Dashboard> Sitzungen
  3. Klicken Sie auf das Aktualisierungssymbol
  4. Klicken Sie neben jedem Vorgang auf das Symbol zum Löschen (x), um sie zu beenden

Sollte nun in der Lage sein, die Datenbank zu löschen.

Andrew
quelle
Dies funktioniert gut - ich habe es mit PgAdmin 4.5 und mit PostgreSQL 11.2 getestet, kompiliert von Visual C ++ Build 1914, 64-Bit (Windows).
vab2048
2
Dies ist die beste Lösung, denke ich. Das funktioniert wirklich gut!
Lahiru
10

Wenn keine potenziellen Auswirkungen auf andere Dienste auf Ihrem Computer auftreten, einfach service postgresql restart

ScotchAndSoda
quelle
8

Lösung:
1. Fahren Sie den Pg-Server herunter. 2. Die Verbindung wird unterbrochen. 3. Starten Sie den Pg-Server neu. 4. Versuchen Sie Ihren Befehl
Geben Sie hier die Bildbeschreibung ein



amoljdv06
quelle
Dies funktionierte auch bei Postgress.app auf einem Mac. In diesem Fall stoppen / starten Sie den Server
Juan José Ramírez
7

So einfach ist das

sudo service postgresql restart
OdkoPP
quelle
3

In meinem Fall verwende ich AWS Redshift (basierend auf Postgres). Und es scheint, dass es keine anderen Verbindungen zur Datenbank gibt, aber ich erhalte den gleichen Fehler.

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

In meinem Fall scheint der Datenbankcluster noch einige Verarbeitungsvorgänge für die Datenbank durchzuführen, und obwohl keine anderen externen / Benutzerverbindungen bestehen, wird die Datenbank weiterhin intern verwendet. Ich habe dies gefunden, indem ich Folgendes ausgeführt habe:

SELECT * FROM stv_sessions;

Mein Hack bestand also darin, eine Schleife in meinen Code zu schreiben und nach Zeilen mit meinem Datenbanknamen zu suchen. (Natürlich ist die Schleife nicht unendlich und ist eine verschlafene Schleife usw.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Wenn Zeilen gefunden wurden, löschen Sie jede PID nacheinander.

SELECT pg_terminate_backend(PUT_PID_HERE);

Wenn keine Zeilen gefunden wurden, löschen Sie die Datenbank

DROP DATABASE XYZ;

Hinweis: In meinem Fall schreibe ich Java-Unit- / Systemtests, bei denen dies als akzeptabel angesehen werden kann. Dies ist für den Produktionscode nicht akzeptabel.


Hier ist der komplette Hack in Java (ignoriere meine Test- / Utility-Klassen).

  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);
    }
  }
Sagan
quelle
2

Meiner Meinung nach laufen im Hintergrund einige Leerlaufabfragen.

  1. Versuchen Sie zuerst, laufende Abfragen anzuzeigen
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. Leerlaufabfrage beenden (Überprüfen Sie, ob sie auf die betreffende Datenbank verweisen, oder ob Sie alle abbrechen oder eine bestimmte mit der PID aus den ausgewählten Ergebnissen beenden können.)

SELECT pg_terminate_backend (procpid);

Hinweis: Das Beenden einer ausgewählten Abfrage hat keine negativen Auswirkungen

Joweria
quelle
2

REVOKE CONNECTverhindert nicht die Verbindungen vom Datenbankbesitzer oder Superuser. Wenn Sie also nicht möchten, dass jemand die Datenbank verbindet, kann der Befehl follow hilfreich sein.

alter database pilot allow_connections = off;

Dann benutze:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';
Inferno
quelle
1
Danke ... REVOKE CONNECT war in meinem Szenario nicht genug.
Volpato
1

Während ich die beiden Antworten mit der höchsten Bewertung bei anderen Gelegenheiten nützlich fand, bestand der einfachste Weg, das Problem zu lösen, darin, zu erkennen, dass PyCharm möglicherweise eine Sitzung offen hält, und wenn ich Stopauf PyCharm klickte , könnte dies hilfreich sein. Bei geöffnetem pgAdmin4 im Browser tat ich dies und sah fast sofort, dass die Statistiken der Datenbanksitzungen auf 0 fielen. Zu diesem Zeitpunkt konnte ich die Datenbank löschen.

hlongmore
quelle
"PyCharm hält möglicherweise eine Sitzung offen"? Wie? Ich führe Unit-Tests in PyCharms Terminal durch (Frontend Python mit Peewee, Backend Postgres), dh die Schaltfläche "Stop" ist ausgegraut und ich behalte diese Fehler trotzdem ...
Laryx Decidua
@LaryxDecidua Ich glaube, dass in meinem Fall eine Instanz eines Dienstes in PyCharm ausgeführt wurde, der die Datenbank verwendet hat. Wenn Sie PyCharm beenden, sinkt die Anzahl der Instanzen auf 0, sodass Sie die Datenbank löschen können? In diesem Fall muss noch etwas verbunden sein (Datenbank-Explorer, SQL-Abfrage, etwas anderes).
Hlongmore
0

Versuchen Sie unter macOS, die postgresql-Datenbank über die Konsole mit dem folgenden Befehl neu zu starten:

brew services restart postgresql
Felipe Corredor
quelle
-1

Versuchen Sie im Terminal diesen Befehl:

ps -ef | grep postgres

Sie werden sehen wie:

501 1445 3645 0 00:05 0: 00.03 postgres: sasha dbname [local] idle

Die dritte Nummer (3645) ist PID.

Sie können dies löschen

sudo kill -9 3645

Und danach starten Sie Ihre PostgreSQL-Verbindung.

Manuell starten:

pg_ctl -D /usr/local/var/postgres start
Alexandr
quelle