Terminate all connections from specific schema in certain database - postgresql

With this command I can terminate all connections running in a specific database.
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'DATABASE_NAME'
AND pid <> pg_backend_pid();
Is there a way to terminate connections in a certain schema only?

No. PostgreSQL connections are always to a database, not to a schema.
Related question on dba.SE:
Force drop db while others may be connected

Related

Deleting a database in Postgres with DBeaver [duplicate]

I need to write a script that will drop a PostgreSQL database. There may be a lot of connections to it, but the script should ignore that.
The standard DROP DATABASE db_name query doesn't work when there are open connections.
How can I solve the problem?
This will drop existing connections except for yours:
Query pg_stat_activity and get the pid values you want to kill, then issue SELECT pg_terminate_backend(pid int) to them.
PostgreSQL 9.2 and above:
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
AND pid <> pg_backend_pid();
PostgreSQL 9.1 and below:
SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
AND procpid <> pg_backend_pid();
Once you disconnect everyone you will have to disconnect and issue the DROP DATABASE command from a connection from another database aka not the one your trying to drop.
Note the renaming of the procpid column to pid. See this mailing list thread.
In PostgreSQL 9.2 and above, to disconnect everything except your session from the database you are connected to:
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
AND pid <> pg_backend_pid();
In older versions it's the same, just change pid to procpid. To disconnect from a different database just change current_database() to the name of the database you want to disconnect users from.
You may want to REVOKE the CONNECT right from users of the database before disconnecting users, otherwise users will just keep on reconnecting and you'll never get the chance to drop the DB. See this comment and the question it's associated with, How do I detach all other users from the database.
If you just want to disconnect idle users, see this question.
PostgreSQL 13 introduced FORCE option.
DROP DATABASE
DROP DATABASE drops a database ... Also, if anyone else is connected to the target database, this command will fail unless you use the FORCE option described below.
FORCE
Attempt to terminate all existing connections to the target database. It doesn't terminate if prepared transactions, active logical replication slots or subscriptions are present in the target database.
DROP DATABASE db_name WITH (FORCE);
Easy Peasy.
I just restart the service in Ubuntu to disconnect connected clients.
sudo service postgresql stop
sudo service postgresql start
psql
DROP DATABASE DB_NAME;
You could kill all connections before dropping the database using the pg_terminate_backend(int) function.
You can get all running backends using the system view pg_stat_activity
I'm not entirely sure, but the following would probably kill all sessions:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'
Of course you may not be connected yourself to that database
Depending on your version of postgresql you might run into a bug, that makes pg_stat_activity to omit active connections from dropped users. These connections are also not shown inside pgAdminIII.
If you are doing automatic testing (in which you also create users) this might be a probable scenario.
In this case you need to revert to queries like:
SELECT pg_terminate_backend(procpid)
FROM pg_stat_get_activity(NULL::integer)
WHERE datid=(SELECT oid from pg_database where datname = 'your_database');
NOTE: In 9.2+ you'll have change procpid to pid.
I noticed that postgres 9.2 now calls the column pid rather than procpid.
I tend to call it from the shell:
#!/usr/bin/env bash
# kill all connections to the postgres server
if [ -n "$1" ] ; then
where="where pg_stat_activity.datname = '$1'"
echo "killing all connections to database '$1'"
else
echo "killing all connections to database"
fi
cat <<-EOF | psql -U postgres -d postgres
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
${where}
EOF
Hope that is helpful. Thanks to #JustBob for the sql.
PostgreSQL 9.2 and above:
SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'
Here's my hack... =D
# Make sure no one can connect to this database except you!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "UPDATE pg_database SET datallowconn=false WHERE datname='<DATABASE_NAME>';"
# Drop all existing connections except for yours!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '<DATABASE_NAME>' AND pid <> pg_backend_pid();"
# Drop database! =D
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "DROP DATABASE <DATABASE_NAME>;"
I put this answer because include a command (above) to block new connections and because any attempt with the command...
REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;
... do not works to block new connections!
Thanks to #araqnid #GoatWalker ! =D
https://stackoverflow.com/a/3185413/3223785
In Linux command Prompt, I would first stop all postgresql processes that are running by tying this command
sudo /etc/init.d/postgresql restart
type the command
bg to check if other postgresql processes are still running
then followed by dropdb dbname to drop the database
sudo /etc/init.d/postgresql restart
bg
dropdb dbname
This works for me on linux command prompt
In my case i had to execute a command to drop all connections including my active administrator connection
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
which terminated all connections and show me a fatal ''error'' message :
FATAL: terminating connection due to administrator command SQL state: 57P01
After that it was possible to drop the database
Nothing worked for me except, I loggined using pgAdmin4 and on the Dashboard I disconnected all connections except pgAdmin4 and then was able to rename by right lick on the database and properties and typed new name.

Unable to drop database postgres RDS instance

I'm a bit confused about why I can't drop my database, so after connecting to my rds postgres instance with
psql --host=mu_user.amazonaws.com --port=5432 --username=my_user --password --dbname=postgres
I've REVOKED new connection to the db I want to drop with
REVOKE CONNECT ON DATABASE mydb FROM public;
then I have terminated all connection with
SELECT pid, pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'mydb' AND pid <> pg_backend_pid();
after that when I want to drop the db I still can't because It will say
ERROR: database "mydb" is being accessed by other users
DETAIL: There are 10 other sessions using the database.
If I inspect live connections with
SELECT
pid
,datname
,usename
,application_name
,client_hostname
,client_port
,backend_start
,query_start
,query
,state
FROM pg_stat_activity
WHERE state = 'active';
there will be none, but if I change active to idle I can see a bunch, and after trying to kill them with pg_terminate_backend(pid) I again can't drop the db and I again have the same ERROR, so can someone please help me understand what I'm I doing wrong here?
Those connections which are idle and always appearing are by my_user, who is also a superuser.
The problem is that those other connections are by a superuser, and superusers are exempt from permission checks, so revoking the CONNECT privilege on the database won't keep these guys out.
You could either block the connections via pg_hba.conf, or you can run both statements immediately after each other:
SELECT pg_terminate_backend(pid) FROM pg_stat_activity; DROP DATABASE mydb;
in the hope that the users won't have time to reconnect before the DROP DATABASE hits.

How many dblink connections can be opened in postgres

As autonomus transactions are not avaliable in postgres we are using dblink as a workaroud but there is a scenerio which is as
linked from Does Postgres support nested or autonomous transactions?
select * from dblink_connect('TEST1','host=localhost port=5432 dbname=tyguy user=postgres password=postgres') as t1(text);
Then when we use the method
SELECT dblink_get_connections();
then only one connection is visible that is absolutely correct named as 'TEST1'
but when i open a new pg admin window or a new session then the same is not avaliable as
SELECT dblink_get_connections();
returns empty. No connection of name 'TEST1'
I am confused is DBlink is at database level ? or session level .
if it is at session level then how many dblink named connections can be opened in a database.

Trying to rename a database in Redshift cluster

I'm trying to rename a database in my Redshift cluster.
You cannot rename the database when you're connected to it so I've created a temporary database, reconnected with SQL Workbench to the temporary db and issued:
ALTER DATABASE olddb RENAME to newdb;
I get an error stating ERROR: database "olddb" is being accessed by other users [SQL State=55006]
I've checked who is connected and there appear to be some connections from user rdsdb to the database. I assume this is a service account that AWS Redshift use to perform maintenance tasks etc.
How can I rename the database when this superuser is connected?
Many thanks.
You cannot alter the name of (or delete!) the database that is created during the initial cluster creation. I don't believe this is mentioned in the docs but I've confirmed it with them.
We can change the database name which is already created.
Detailed steps on how to do
Connect to the old database and create a new database if you do not have another one already.
create database databasebasename
In this example, I will call the databasename as 'newdb'.
Connect to newdb using connecting string as, jdbc:redshift://.us-east-1.redshift.amazonaws.com:8192/newdb, with the same password and username of your superuser (or the other eligible users as mentioned above).
Now you can alter the database name. Substitute 'database_name_new' with the desired databasename.
alter database old-db-name rename to database_name_new;
If there are any active sessions, you'll have to kill them. To find the pid of active sessions:
select * from STV_SESSIONS where user_name='rdsdb';
Then to kill a session:
SELECT
pg_terminate_backend(<pid>)
FROM
pg_stat_activity
WHERE
-- don't kill my own connection!
procpid <> pg_backend_pid()
-- don't kill the connections to other databases
AND datname = '<old-db-name>';
Once complete, you can connect back to that new database using the new name in the connection string as
jdbc:redshift://<cluser-id>.us-east-1.redshift.amazonaws.com:8192/database_name_new
You can delete the temporary 'newdb'.
drop database databasebasename
That's possible now -- I just renamed the database that was created during the initial cluster creation.
We had a similar situation.
Step 1: Connect to the database which is not the one you are trying to rename. Check the same by executing SELECT CURRENT_DATABASE();.
Step 2: Execute the query below -
SELECT
ss.*, 'select pg_terminate_backend('||process||');'
FROM
stv_sessions ss
ORDER BY
db_name;
The output of the query will have a column at the end with the select statements. Execute those to kill the sessions.
Step 3(Optional): If you are not the owner of the database try to modify the ownership of the database -
ALTER DATABASE <database to be renamed>
OWNER TO <user which is going to do the rename>;
Step 4: Rename the database

PostgreSQL: Temporarily disable connections

I have a script in PostgreSQL which restores test database from dump every night. The database is accessed by app servers and processes with connection pool which keeps a few connections alive at all times.
So the script restores dump into my_temp_database. Then it should rename my_database to my_old_database, my_temp_database to my_database, and eventually drop my_old_database.
How can I disconnect all clients, superuser or not, from my_database, so that it can be renamed? How I can I temporarily prevent them from reconnecting?
Is there a better way to do what I need?
To mark database 'applogs' as not accepting new connections:
update pg_database set datallowconn = false where datname = 'applogs';
Another possibility would be to revoke 'connect' access on the database for the client role(s).
Disconnect users from database = kill backend. So to disconnect all other users from "applogs" database, for example:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'applogs' and procpid <> pg_backend_pid();
Once you've done both of those, you are the only user connected to 'applogs'. Although there might actually be a delay before the backends actually finish disconnecting?
After you have terminated the current active connections you can also issue this command that will only allow super users to login. This assumes you are ok with all super users having access still. Hopefully you don't hand out super user rights to just anyone.
ALTER DATABASE your_db CONNECTION LIMIT 0;
Starting PostgreSQL 9.5 we finally can:
ALTER DATABASE db WITH ALLOW_CONNECTIONS false;
I had a different usage scenario, in which I wanted to disable a DB for everyone (including superuser) and forever, but not plainly drop it just yet, to be able to reactivate it quickly if needed.
This worked fine on an old 8.3 Postgres:
UPDATE pg_database SET datallowconn=false WHERE datname='my_db_name';
If you are connected in session with the DB that you want to dissallow connecting to, and to stay connected in the same session after you disallow connections, then use this :
UPDATE pg_database SET datallowconn = false WHERE datname = '_db_name_' ;
... which allows you to do stuff without any other connection happening until you re-enable
But if you use this, it must be from in a session in another DB :
ALTER DATABASE _db_name_ WITH ALLOW_CONNECTIONS false ;
(( i realise this is almost a summary of the answers above ))