Postgresql - impossible de supprimer la base de données en raison de certaines connexions automatiques à la base de données

162

Chaque fois que j'essaye de supprimer la base de données, j'obtiens:

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

Quand j'utilise:

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

J'ai mis fin à la connexion à partir de cette base de données, mais si j'essaie de supprimer la base de données après cela, quelqu'un se connecte automatiquement à cette base de données et donne cette erreur. Qu'est-ce qui pourrait faire ça? Personne n'utilise cette base de données, sauf moi.

Andrius
la source

Réponses:

197

Vous pouvez empêcher de futures connexions:

REVOKE CONNECT ON DATABASE thedb FROM public;

(et éventuellement d'autres utilisateurs / rôles; voir \l+dans psql)

Vous pouvez ensuite mettre fin à toutes les connexions à cette base de données sauf la vôtre:

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

Sur les anciennes versions a pidété appelé procpid, vous devrez donc vous en occuper.

Puisque vous avez révoqué des CONNECTdroits, tout ce qui essayait de se connecter automatiquement ne devrait plus pouvoir le faire.

Vous pourrez désormais supprimer la base de données.

Cela ne fonctionnera pas si vous utilisez des connexions de super-utilisateur pour des opérations normales, mais si vous le faites, vous devez d'abord résoudre ce problème.


Une fois que vous avez terminé de supprimer la base de données, si vous créez à nouveau la base de données, vous pouvez exécuter la commande ci-dessous pour restaurer l'accès

GRANT CONNECT ON DATABASE thedb TO public;
Craig Ringer
la source
19
Si vous importez une autre base de données avec le même nom plus tard, accordez la capacité de connexion au public back:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin
156

Chaque fois que j'essaye de supprimer la base de données, j'obtiens:

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

Vous devez d'abord révoquer

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Puis utilisez:

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

Cela fonctionnera sûrement.

Suneel Kumar
la source
5
Cela l'a fait pour moi. Merci
rpivovar
1
Sur place! Je vous remercie! 🎉
slajma
1
A fonctionné parfaitement. Je vous remercie.
Mustafa Magdi le
34

J'ai trouvé une solution à ce problème, essayez d'exécuter cette commande dans le terminal

ps -ef | grep postgres

tuer le processus par cette commande

sudo kill -9 PID
Dinesh Pallapa
la source
Non, c'est trop dur, que faire si vous ne pouvez pas arrêter le processus pg parce que vous avez d'autres bases de données auxquelles vous accédez?
Vladimir Stazhilov
2
@VladimirStazhilov Il affichera le nom de la base de données et le pid de cette base de données. quelqu'un peut sélectionner un pid spécifique pour tuer uniquement cette base de données particulière.
Dinesh Pallapa
29

Vérifiez simplement quelle est la connexion, d'où elle vient. Vous pouvez voir tout cela dans:

select * from pg_stat_activity where datname = 'TARGET_DB';

C'est peut-être votre connexion?


la source
4
sudo kill -9 PID dans le terminal après avoir vu le résultat
Dan Rey Oquindo
25

Cela signifie qu'un autre utilisateur accède à la base de données. Redémarrez simplement PostgreSQL. Cette commande fera l'affaire

root@kalilinux:~#sudo service postgresql restart

Essayez ensuite de supprimer la base de données:

postgres=# drop database test_database;

Ça fera l'affaire.

Suman Astani
la source
11

Solution pgAdmin 4 utilisant l'interface utilisateur

Activez d'abord l'activité d'affichage sur le tableau de bord si vous ne l'avez pas fait:

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

Désactivez maintenant tous les processus utilisant la base de données:

  1. Cliquez sur le nom de la base de données
  2. Cliquez sur Tableau de bord> Sessions
  3. Cliquez sur l'icône d'actualisation
  4. Cliquez sur l'icône de suppression (x) à côté de chaque processus pour y mettre fin

Devrait maintenant pouvoir supprimer le fichier db.

Andrew
la source
Cela fonctionne bien - je l'ai testé avec PgAdmin 4.5 et avec PostgreSQL 11.2, compilé par Visual C ++ build 1914, 64 bits (Windows).
vab2048
2
C'est la meilleure solution que je pense. Cela fonctionne vraiment bien!
Lahiru le
10

Si aucun impact potentiel sur d'autres services de votre machine, il suffit service postgresql restart

ScotchAndSoda
la source
8

Solution:
1. Arrêtez le serveur Pg 2. Il déconnectera toute connexion active 3. Redémarrez le serveur Pg 4. Essayez votre commande
entrez la description de l'image ici



amoljdv06
la source
cela a fonctionné pour moi aussi avec Postgress.app sur un Mac. Dans ce cas, vous arrêtez / redémarrez le serveur
Juan José Ramírez
7

Aussi simple que cela

sudo service postgresql restart
OdkoPP
la source
3

Dans mon cas, j'utilise AWS Redshift (basé sur Postgres). Et il semble qu'il n'y ait pas d'autres connexions à la base de données, mais j'obtiens la même erreur.

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

Dans mon cas, il semble que le cluster de bases de données effectue toujours un traitement sur la base de données, et bien qu'il n'y ait pas d'autres connexions externes / utilisateur, la base de données est toujours utilisée en interne. J'ai trouvé cela en exécutant ce qui suit:

SELECT * FROM stv_sessions;

Mon hack consistait donc à écrire une boucle dans mon code, à la recherche de lignes contenant le nom de ma base de données. (bien sûr, la boucle n'est pas infinie et est une boucle endormie, etc.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Si des lignes sont trouvées, procédez à la suppression de chaque PID, un par un.

SELECT pg_terminate_backend(PUT_PID_HERE);

Si aucune ligne n'est trouvée, procédez à la suppression de la base de données

DROP DATABASE XYZ;

Remarque: Dans mon cas, j'écris des tests unitaires / système Java, où cela pourrait être considéré comme acceptable. Ce n'est pas acceptable pour le code de production.


Voici le hack complet, en Java (ignorez mes classes de test / utilitaires).

  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
la source
2

À mon avis, il y a des requêtes inactives en cours d'exécution dans le backgroud.

  1. Essayez d'abord d'afficher les requêtes en cours d'exécution
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 (Vérifiez s'ils font référence à la base de données en question ou vous pouvez tous les tuer ou en tuer un spécifique en utilisant le pid des résultats de sélection)

SELECT pg_terminate_backend (procpid);

Remarque: la suppression d'une requête de sélection n'a aucun impact négatif

Joweria
la source
2

REVOKE CONNECTn'empêchera pas les connexions du propriétaire de la base de données ou du superutilisateur. Donc, si vous ne voulez pas que quiconque connecte la base de données, la commande follow peut être utile.

alter database pilot allow_connections = off;

Puis utilisez:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';
enfer
la source
1
Merci ... REVOKE CONNECT n'était pas suffisant sur mon scénario.
volpato le
1

Bien que j'ai trouvé les deux réponses aux votes complémentaires utiles à d'autres occasions, aujourd'hui, le moyen le plus simple de résoudre le problème était de réaliser que PyCharm pouvait garder une session ouverte, et si je Stopcliquais dans PyCharm, cela pourrait aider. Avec pgAdmin4 ouvert dans le navigateur, je l'ai fait et j'ai presque immédiatement vu les statistiques des sessions de base de données tomber à 0, auquel cas j'ai pu supprimer la base de données.

hlongmore
la source
"PyCharm pourrait garder une session ouverte"? Comment? Je lance des tests unitaires dans le terminal de PyCharm (frontend Python avec peewee, backend Postgres), c'est à dire que le bouton "Stop" est grisé et je garde quand même ces erreurs ...
Laryx Decidua
@LaryxDecidua Je crois que, dans mon cas, j'ai dû avoir une instance d'un service fonctionnant dans PyCharm qui utilisait la base de données. Si vous quittez PyCharm, le nombre d'instances tombe-t-il à 0, vous permettant de supprimer la base de données? Si c'est le cas, il doit y avoir quelque chose (explorateur de base de données, requête SQL, autre chose) qui est toujours connecté.
hlongmore
1

Dans macOS, essayez de redémarrer la base de données postgresql via la console à l'aide de la commande:

brew services restart postgresql
Felipe Corredor
la source
-1

Dans le terminal, essayez cette commande:

ps -ef | grep postgres

vous verrez comme:

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

Le troisième nombre (3645) est PID.

Vous pouvez supprimer ceci

sudo kill -9 3645

Et après cela, démarrez votre connexion PostgreSQL.

Démarrez manuellement:

pg_ctl -D /usr/local/var/postgres start
Alexandr
la source