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


(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

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

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:

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.