Postgresql: no se puede eliminar la base de datos debido a algunas conexiones automáticas a DB


162

Cada vez que intento soltar la base de datos obtengo:

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

Cuando uso:

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

Terminé la conexión desde esa base de datos, pero si trato de eliminar la base de datos después de eso, de alguna manera alguien se conecta automáticamente a esa base de datos y da este error. ¿Qué podría estar haciendo eso? Nadie usa esta base de datos, excepto yo.

Respuestas:


197

Puede evitar futuras conexiones:

REVOKE CONNECT ON DATABASE thedb FROM public;

(y posiblemente otros usuarios / roles; ver \l+en psql)

A continuación, puede finalizar todas las conexiones a esta base de datos, excepto la suya:

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

En versiones anteriores pidse llamaba, procpidasí que tendrás que lidiar con eso.

Dado que ha revocado los CONNECTderechos, lo que sea que intentara conectarse automáticamente ya no debería poder hacerlo.

Ahora podrá soltar la base de datos.

Esto no funcionará si está utilizando conexiones de superusuario para operaciones normales, pero si lo está haciendo, primero debe solucionar ese problema.


Una vez que haya terminado de soltar la base de datos, si vuelve a crear la base de datos, puede ejecutar el siguiente comando para restaurar el acceso

GRANT CONNECT ON DATABASE thedb TO public;

19
Si importa otra base de datos con el mismo nombre más adelante, otorgue la capacidad de conexión al respaldo público:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin

156

Cada vez que intento soltar la base de datos obtengo:

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

Primero necesitas revocar

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Luego use:

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

Seguramente funcionará.


55
Esto lo hizo por mi. Gracias
rpivovar

1
¡Correcto! ¡Gracias! 🎉
slajma

1
Funcionó perfecto. Gracias.
Mustafa Magdi

34

Encontré una solución para este problema, intente ejecutar este comando en la terminal

ps -ef | grep postgres

matar proceso por este comando

sudo kill -9 PID

No, es demasiado hardcode, ¿qué pasa si no puede procesar kiil pg porque tiene otras bases de datos a las que se está accediendo?
Vladimir Stazhilov

2
@VladimirStazhilov Mostrará el nombre de la base de datos y el pid de esa base de datos. alguien puede seleccionar pid pid kill solo para esa base de datos en particular.
Dinesh Pallapa

29

Simplemente verifique cuál es la conexión, de dónde viene. Puedes ver todo esto en:

select * from pg_stat_activity where datname = 'TARGET_DB';

Tal vez es tu conexión?


44
sudo kill -9 PID en la terminal después de ver el resultado
Dan Rey Oquindo

25

Significa que otro usuario está accediendo a la base de datos. Simplemente reinicie PostgreSQL. Este comando hará el truco

root@kalilinux:~#sudo service postgresql restart

Luego intente soltar la base de datos:

postgres=# drop database test_database;

Esto hará el truco.


11

Solución pgAdmin 4 usando UI

Primero habilite mostrar actividad en el tablero si no ha:

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

Ahora deshabilite todos los procesos usando el db:

  1. Haga clic en el nombre de la base de datos
  2. Haga clic en Panel de control> Sesiones
  3. Haga clic en el icono de actualización
  4. Haga clic en el ícono eliminar (x) al lado de cada proceso para finalizarlos

Ahora debería poder eliminar la base de datos.


Esto funciona bien: lo probé con PgAdmin 4.5 y con PostgreSQL 11.2, compilado por Visual C ++ build 1914, 64 bits (Windows).
vab2048

2
Esta es la mejor solución, creo. ¡Esto funciona muy bien!
Lahiru

10

Si no hay un impacto potencial en otros servicios en su máquina, simplemente service postgresql restart


8

Solución:
1. Apague el servidor Pg 2. Desconectará toda la conexión activa 3. Reinicie el servidor Pg 4. Pruebe su comando
ingrese la descripción de la imagen aquí




Esto también funcionó para mí con Postgress.app en una Mac. En ese caso, detiene / inicia el servidor
Juan José Ramírez


3

En mi caso, estoy usando AWS Redshift (basado en Postgres). Y parece que no hay otras conexiones a la base de datos, pero estoy recibiendo este mismo error.

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

En mi caso, parece que el clúster de la base de datos todavía está procesando algo en la base de datos, y aunque no hay otras conexiones externas / de usuario, la base de datos todavía está en uso interno. Encontré esto ejecutando lo siguiente:

SELECT * FROM stv_sessions;

Entonces, mi truco fue escribir un bucle en mi código, buscando filas con el nombre de mi base de datos. (por supuesto, el bucle no es infinito, y es un bucle adormecido, etc.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Si se encuentran filas, proceda a eliminar cada PID, uno por uno.

SELECT pg_terminate_backend(PUT_PID_HERE);

Si no se encuentran filas, proceda a descartar la base de datos.

DROP DATABASE XYZ;

Nota: en mi caso, estoy escribiendo pruebas de unidad / sistema Java, donde esto podría considerarse aceptable. Esto no es aceptable para el código de producción.


Aquí está el hack completo, en Java (ignore mis clases de prueba / utilidad).

  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

En mi opinión, hay algunas consultas inactivas que se ejecutan en el fondo.

  1. Intente mostrar consultas en ejecución primero
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 (verifique si están haciendo referencia a la base de datos en cuestión o si puede matarlos a todos o matar a un específico utilizando el pid de los resultados seleccionados)

SELECCIONE pg_terminate_backend (procpid);

Nota: matar una consulta de selección no tiene ningún impacto negativo


2

REVOKE CONNECTno impedirá las conexiones del propietario o superusuario de db. Por lo tanto, si no desea que nadie conecte la base de datos, puede ser útil seguir el comando.

alter database pilot allow_connections = off;

Luego use:

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

1
Gracias ... REVOKE CONNECT no fue suficiente en mi escenario.
Volpato

1

Si bien encontré que las dos respuestas con votos superiores fueron útiles en otras ocasiones, hoy en día, la forma más sencilla de resolver el problema era darse cuenta de que PyCharm podría mantener una sesión abierta, y si hice clic Stopen PyCharm, eso podría ayudar. Con pgAdmin4 abierto en el navegador, lo hice, y casi de inmediato vi que las estadísticas de las sesiones de la Base de datos cayeron a 0, momento en el que pude soltar la base de datos.


¿"PyCharm podría estar manteniendo una sesión abierta"? ¿Cómo? Ejecuto pruebas unitarias en la terminal de PyCharm (interfaz Python con peewee, backend Postgres), es decir, el botón "Stop" está atenuado y no obstante mantengo estos errores ...
Laryx Decidua

@LaryxDecidua Creo que, en mi caso, debo haber tenido una instancia de un servicio que se ejecuta en PyCharm que utilizaba la base de datos. Si sale de PyCharm, ¿el número de instancias cae a 0, lo que le permite soltar la base de datos? Si es así, debe haber algo (explorador de base de datos, consulta SQL, algo más) que todavía esté conectado.
hlongmore

1

En macOS, intente reiniciar la base de datos postgresql a través de la consola con el comando:

brew services restart postgresql

-1

En la terminal prueba este comando:

ps -ef | grep postgres

verás como:

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

El tercer número (3645) es PID.

Puedes borrar esto

sudo kill -9 3645

Y después de eso, inicie su conexión PostgreSQL.

Comience manualmente:

pg_ctl -D /usr/local/var/postgres start
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.