Postgresql - impossibile eliminare il database a causa di alcune connessioni automatiche al DB


162

Ogni volta che provo a eliminare il database ottengo:

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

Quando uso:

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

Ho terminato la connessione da quel DB, ma se provo a eliminare il database dopo che in qualche modo qualcuno si connette automaticamente a quel database e dà questo errore. Cosa potrebbe farlo? Nessuno usa questo database, tranne me.

Risposte:


197

Puoi impedire connessioni future:

REVOKE CONNECT ON DATABASE thedb FROM public;

(e possibilmente altri utenti / ruoli; vedere \l+in psql)

È quindi possibile terminare tutte le connessioni a questo db tranne il proprio:

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

Nelle versioni precedenti è pidstato chiamato, procpidquindi dovrai occupartene.

Dal momento che hai revocato i CONNECTdiritti, qualunque cosa stesse provando a connettersi automaticamente non dovrebbe più essere in grado di farlo.

Ora sarai in grado di eliminare il DB.

Questo non funzionerà se stai usando connessioni superutente per le normali operazioni, ma se lo stai facendo devi prima risolvere quel problema.


Dopo aver eliminato il database, se si crea nuovamente il database, è possibile eseguire il comando seguente per ripristinare l'accesso

GRANT CONNECT ON DATABASE thedb TO public;

19
Se si importa un altro database con lo stesso nome in un secondo momento, concedere la capacità di connessione al pubblico:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin,

156

Ogni volta che provo a eliminare il database ottengo:

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

Per prima cosa devi revocare

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Quindi utilizzare:

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

Funzionerà sicuramente.


5
Questo è stato per me. Grazie
rpivovar il

1
Spot on! Grazie! 🎉
slajma,

1
Ha funzionato perfettamente. Grazie.
Mustafa Magdi,

34

Ho trovato una soluzione per questo problema provare a eseguire questo comando nel terminale

ps -ef | grep postgres

uccidi processo con questo comando

sudo kill -9 PID

No, è troppo hardcode, cosa succede se non riesci a elaborare il processo pg perché hai altri database a cui si accede?
Vladimir Stazhilov,

2
@VladimirStazhilov Mostrerà il nome e il pid del database. qualcuno può selezionare pid kill specifico solo quel particolare database.
Dinesh Pallapa,

29

Controlla semplicemente qual è la connessione, da dove proviene. Puoi vedere tutto questo in:

select * from pg_stat_activity where datname = 'TARGET_DB';

Forse è la tua connessione?


4
sudo uccide -9 PID nel terminale dopo aver visto il risultato
Dan Rey Oquindo il

25

Significa che un altro utente sta accedendo al database. Basta riavviare PostgreSQL. Questo comando farà il trucco

root@kalilinux:~#sudo service postgresql restart

Quindi prova a eliminare il database:

postgres=# drop database test_database;

Questo farà il trucco.


11

pgAdmin 4 soluzione utilizzando l'interfaccia utente

Per prima cosa abilita Mostra attività sulla dashboard se non hai:

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

Ora disabilita tutti i processi usando il db:

  1. Fai clic sul nome del DB
  2. Fai clic su Dashboard> Sessioni
  3. Fai clic sull'icona di aggiornamento
  4. Fare clic sull'icona Elimina (x) accanto a ciascun processo per terminarli

Ora dovrebbe essere in grado di eliminare il db.


Funziona bene: l'ho testato con PgAdmin 4.5 e PostgreSQL 11.2, compilato da Visual C ++ build 1914, 64 bit (Windows).
vab2048,

2
Questa è la migliore soluzione che penso. Funziona davvero bene!
Lahiru,

10

Se nessun potenziale impatto su altri servizi sulla tua macchina, semplicemente service postgresql restart


8

Soluzione:
1. Arrestare il server Pg 2. Disconnetterà tutta la connessione attiva 3. Riavviare il server Pg 4. Provare il comando
inserisci qui la descrizione dell'immagine




questo ha funzionato anche per me con Postgress.app su un Mac. In tal caso, arrestare / avviare il server
Juan José Ramírez, il

7

Semplice come quella

sudo service postgresql restart

3

Nel mio caso, sto usando AWS Redshift (basato su Postgres). E sembra che non ci siano altre connessioni al DB, ma sto ottenendo lo stesso errore.

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

Nel mio caso, sembra che il cluster di database stia ancora eseguendo alcune elaborazioni sul database e, sebbene non vi siano altre connessioni esterne / utente, il database è ancora in uso internamente. Ho trovato questo eseguendo il seguente:

SELECT * FROM stv_sessions;

Quindi il mio hack è stato quello di scrivere un ciclo nel mio codice, cercando le righe con il mio nome di database all'interno. (ovviamente il ciclo non è infinito, ed è un ciclo assonnato, ecc.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Se vengono rilevate righe, procedere con l'eliminazione di ogni PID, uno per uno.

SELECT pg_terminate_backend(PUT_PID_HERE);

Se non viene trovata alcuna riga, procedere con l'eliminazione del database

DROP DATABASE XYZ;

Nota: nel mio caso, sto scrivendo test di unità / sistema Java, dove questo potrebbe essere considerato accettabile. Questo non è accettabile per il codice di produzione.


Ecco l'hack completo, in Java (ignora le mie classi test / utility).

  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

Secondo me ci sono alcune domande inattive in esecuzione nel backgroud.

  1. Prova a mostrare prima le query in esecuzione
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. kill idle query (Controlla se fanno riferimento al database in questione o puoi ucciderli tutti o uccidere uno specifico usando il pid dai risultati selezionati)

SELEZIONA pg_terminate_backend (procpid);

Nota: l' uccisione di una query selezionata non ha alcun impatto negativo


2

REVOKE CONNECTnon impedirà le connessioni dal proprietario del database o dal superutente. Quindi se non vuoi che nessuno colleghi il db, seguire il comando può essere utile.

alter database pilot allow_connections = off;

Quindi utilizzare:

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

1
Grazie ... REVOKE CONNECT non è stato abbastanza sul mio scenario.
volpato,

1

Mentre ho trovato utili le due risposte più votate in altre occasioni, oggi, il modo più semplice per risolvere il problema era rendersi conto che PyCharm avrebbe potuto tenere aperta una sessione, e se avessi cliccato Stopsu PyCharm, ciò avrebbe potuto essere d'aiuto. Con pgAdmin4 aperto nel browser, l'ho fatto e quasi immediatamente ho visto le statistiche delle sessioni del database scendere a 0, a quel punto sono stato in grado di eliminare il database.


"PyCharm potrebbe tenere aperta una sessione"? Come? Eseguo test unitari nel terminale di PyCharm (frontend Python con peewee, backend Postgres), ovvero il pulsante "Stop" è disattivato e mantengo comunque questi errori ...
Laryx Decidua

@LaryxDecidua Credo che, nel mio caso, avrei dovuto avere un'istanza di un servizio in esecuzione in PyCharm che utilizzava il db. Se si esce da PyCharm, il numero di istanze scende a 0, consentendo di eliminare il db? In tal caso, ci deve essere qualcosa (Esplora database, query SQL, qualcos'altro) che è ancora connesso.
hlongmore,

1

In macOS prova a riavviare il database postgresql tramite la console usando il comando:

brew services restart postgresql

-1

Nel terminale provare questo comando:

ps -ef | grep postgres

vedrai come:

501 1445 3645 0 12:05 0: 00.03 postgres: sasha dbname [local] inattivo

Il terzo numero (3645) è PID.

Puoi cancellare questo

sudo kill -9 3645

E dopo avvia la tua connessione PostgreSQL.

Inizia manualmente:

pg_ctl -D /usr/local/var/postgres start
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.