PostgreSQL
Migrate Database
Find Settings of existing Database
sudo -u postgres psql --cluster <version>/main
-- Database-level info
\l+ your_database
-- Server-wide settings
SHOW SERVER_ENCODING;
SHOW LC_COLLATE;
SHOW LC_CTYPE;
-- Installed extensions
\dx
-- Example Output
Name | Owner | Encoding | Collate | Ctype | Access privileges
----------+----------+----------+------------+------------+--------------------
your_database | appuser | UTF8 | en_US.utf8 | en_US.utf8 |
Export existing Database
sudo -u postgres pg_dump -h <server> -p <port> -U <user> -W -Fc -f <output file> <database>
-h = Hostname
-p = Port
-U = Username
-W = Prompt for Password
-Fc = pg_dump non-Text-Format (required for pg_restore)
-f = Output File
- Command needs to be run with
sudo -u postgresas the postgres User has (as default) only local Access and only direct Login without any Password.
(Optional) Copy to new Server
scp <path-to-dump> <user>@<server>:/tmp/<filename.dump>
Create User on new Database
sudo -u postgres psql --cluster <version>/main -c "CREATE USER <username> WITH PASSWORD '<password>';"
Create (empty) Database
Restore Database
sudo -u postgres pg_restore -h <server> -p <port> -U <user> -d <database> -c <input_file>
-h = Hostname
-p = Port
-U = Username
-W = Prompt for Password
-d = (New) Database Name
-c = Input File
Backup Database
Find Database to Backup
1. List all Postgres Instances:
pg_lsclusters
root@SRV-PSQL-PRD-01:~# pg_lsclusters
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "de_DE.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
Ver Cluster Port Status Owner Data directory Log file
13 main 5432 online postgres /var/lib/postgresql/13/main /var/log/postgresql/postgresql-13-main.log
15 main 5433 online postgres /var/lib/postgresql/15/main /var/log/postgresql/postgresql-15-main.log
2. Connect to Cluster
sudo -u postgres psql --cluster <version>/<release>
root@SRV-PSQL-PRD-01:~# sudo -u postgres psql --cluster 15/main
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "de_DE.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
could not change directory to "/root": Permission denied
psql (15.14 (Debian 15.14-1.pgdg12+1))
Type "help" for help.
3. List Databases
\du
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
forgejo | Create DB | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
zabbix |
4. Disconnect
\q
Create Backup of Database
Access Instance by Port
1. Identify Instance Port
pg_lsclusters
root@db-psql-prd-01:~# pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
13 main 5432 online postgres /var/lib/postgresql/13/main /var/log/postgresql/postgresql-13-main.log
15 main 5433 online postgres /var/lib/postgresql/15/main /var/log/postgresql/postgresql-15-main.log
18 main 5434 online postgres /var/lib/postgresql/18/main /var/log/postgresql/postgresql-18-main.log
2. Open Connection to specific Instance using Port
Host-to-Host Connections
psql -h <REMOTE HOST> -p <REMOTE PORT> -U <DB_USER> <DB_NAME>
Localhost Connections using local-only Authentication
sudo -u postgres psql -P <PORT> [...]
pgadmin4
Reset Admin Password
List Users
sudo /usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py get-users
Set Password
sudo /usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py update-user <e-mail> --password <password> --role <Current Role>
Create Application Database
Creating a Postgres Database for an Application (CLI)
Option 1: DBA creates the database directly
Use this when the app should not be able to create/drop databases itself (recommended for most production apps).
sudo -u postgres psql
-- Create a dedicated role for the app
CREATE ROLE app_user WITH LOGIN PASSWORD 'strong_password_here';
-- Create the database, owned by that role
CREATE DATABASE app_db OWNER app_user;
-- Restrict connections to only this DB for that user
REVOKE ALL ON DATABASE app_db FROM PUBLIC;
GRANT CONNECT ON DATABASE app_db TO app_user;
-- Optional: default schema privileges
\c app_db
GRANT ALL ON SCHEMA public TO app_user;
Use case: app just needs a schema to read/write. Least privilege, no CREATEDB right.
Option 2: Role with CREATEDB permission
Use this when the app (or a deployment pipeline / ORM migration tool) needs to create its own database, e.g. CI/CD, multi-tenant provisioning.
CREATE ROLE app_user WITH LOGIN PASSWORD 'strong_password_here' CREATEDB;
Then the app itself (or its migration tool) can run:
CREATE DATABASE app_db OWNER app_user;
Trade-off: convenient for automation, but CREATEDB lets that role create any number of databases on the cluster — scope it to a dedicated role per app, never reuse across apps.
Adjusting pg_hba.conf
Location depends on install method:
sudo -u postgres psql -c "SHOW hba_file;"
Add a line above any broader/catch-all rule (order matters — first match wins):
# TYPE DATABASE USER ADDRESS METHOD
host app_db app_user 10.0.0.0/24 scram-sha-256
- Use
scram-sha-256(notmd5) unless you have a compatibility reason not to. - Restrict
ADDRESSto the actual app subnet/host — avoid0.0.0.0/0. - For local Unix-socket app connections on the same host:
local app_db app_user scram-sha-256
Reload (no restart needed):
sudo -u postgres psql -c "SELECT pg_reload_conf();"
# or
sudo systemctl reload postgresql
Managing Multiple Postgres Instances on One Host (e.g. v15 + v18)
Debian/Ubuntu's postgresql-common framework handles this natively via clusters, each with its own port, data dir, config, and pg_hba.conf.
List all clusters:
pg_lsclusters
Example output:
Ver Cluster Port Status Owner Data directory Log file
15 main 5432 online postgres /var/lib/postgresql/15/main ...
18 main 5433 online postgres /var/lib/postgresql/18/main ...
Key points:
- Each version gets its own port automatically (5432, 5433, ...) — no manual port juggling needed.
- Config files live under
/etc/postgresql/<version>/<cluster>/—pg_hba.confandpostgresql.confare per-instance, edit the correct version's file. - Connect to a specific instance with
-p:psql -h localhost -p 5433 -U app_user -d app_db - Manage individual clusters:
sudo pg_ctlcluster 18 main reload sudo systemctl restart postgresql@18-main - If not using Debian's cluster tooling (e.g. compiled from source or RPM-based), you must manually assign distinct
port,data_directory, andunix_socket_directoriesper instance in eachpostgresql.conf, and run each as a separate systemd service/data dir.
Recommendation: decide per-app which major version it targets, keep app roles/DBs isolated to one cluster, and never share a pg_hba.conf between versions — each instance's file only affects its own cluster.