Table of Contents
- PostgreSQL Administration Command Reference
- 1. PostgreSQL Installation
- 2. Connecting to PostgreSQL
- 3. Useful
psqlCommands- Show connection information
- List databases
- Connect to another database
- List PostgreSQL users and roles
- List schemas
- List tables
- List tables in all schemas
- Describe a table
- Show detailed table information
- List indexes
- List sequences
- List views
- Show command history
- Run a SQL file
- Toggle expanded output
- Show query execution time
- Quit
psql
- 4. Database and User Setup
- 5. Schema Setup and Permissions
- Create a schema
- Create a schema only if it does not exist
- Change schema ownership
- Grant access to a schema
- Allow object creation in a schema
- Grant access to all existing tables
- Grant access to all existing sequences
- Set default privileges for future tables
- Set default privileges for future sequences
- 6. Basic Table Creation
- 7. Common Data Commands
- 8. Modifying Tables
- Add a column
- Add a column with a default
- Rename a column
- Change a column data type
- Set a default value
- Remove a default value
- Add a
NOT NULLconstraint - Remove a
NOT NULLconstraint - Add a check constraint
- Drop a constraint
- Rename a table
- Change table ownership
- Drop a column
- Drop a table
- Drop a table only if it exists
- Drop a table and dependent objects
- 9. Transactions
- 10. Inspecting Database Objects
- Database Backups
- Database Restores
- Docker PostgreSQL
- PostgreSQL Authentication and Configuration
- Password Handling
- Backup Automation
- Maintenance and Troubleshooting
- Roles and Security
- Migration Workflow
- Quick Reference
- Backup Checklist
PostgreSQL Administration Command Reference
A practical reference for setting up PostgreSQL, creating databases and users, inspecting schemas, modifying databases, and performing backups and restores.
Replace example values such as
hydra_auctions,hydra_user,localhost, and file paths before running commands.
1. PostgreSQL Installation
RHEL / Rocky Linux / AlmaLinux / Fedora
Install the PostgreSQL client and server packages:
sudo dnf install postgresql postgresql-server
Initialize the database cluster:
sudo postgresql-setup --initdb
Enable and start PostgreSQL:
sudo systemctl enable --now postgresql
Check service status:
sudo systemctl status postgresql
Check installed versions:
psql --version
postgres --version
pg_dump --version
Debian / Ubuntu
sudo apt update
sudo apt install postgresql postgresql-client
sudo systemctl enable --now postgresql
2. Connecting to PostgreSQL
Connect as the local PostgreSQL administrator
sudo -u postgres psql
Connect to a specific database
sudo -u postgres psql -d hydra_auctions
Connect with a PostgreSQL username
psql -U hydra_user -d hydra_auctions
Connect to a remote PostgreSQL server
psql -h 192.168.1.50 -p 5432 -U hydra_user -d hydra_auctions
Force a password prompt
psql -h localhost -U hydra_user -d hydra_auctions -W
Connect using a PostgreSQL URI
psql "postgresql://hydra_user:password@localhost:5432/hydra_auctions"
Avoid putting real passwords directly in shell history when possible.
3. Useful psql Commands
These commands are entered from inside the psql prompt.
Show connection information
\conninfo
List databases
\l
or:
\list
Connect to another database
\c hydra_auctions
List PostgreSQL users and roles
\du
List schemas
\dn
List tables
\dt
List tables in all schemas
\dt *.*
Describe a table
\d auctions
Show detailed table information
\d+ auctions
List indexes
\di
List sequences
\ds
List views
\dv
Show command history
\s
Run a SQL file
\i /path/to/schema.sql
Toggle expanded output
Useful for wide rows:
\x
Show query execution time
\timing
Quit psql
\q
4. Database and User Setup
Create a PostgreSQL user
Run from psql as an administrator:
CREATE USER hydra_user WITH PASSWORD 'replace-with-secure-password';
Create a login role
CREATE ROLE hydra_user
WITH LOGIN
PASSWORD 'replace-with-secure-password';
Create a database
CREATE DATABASE hydra_auctions;
Create a database owned by a specific user
CREATE DATABASE hydra_auctions
OWNER hydra_user;
Create a database from the shell
sudo -u postgres createdb hydra_auctions
Create a user from the shell
sudo -u postgres createuser --pwprompt hydra_user
Change a user’s password
ALTER USER hydra_user
WITH PASSWORD 'new-secure-password';
Change database ownership
ALTER DATABASE hydra_auctions
OWNER TO hydra_user;
Allow a user to connect to a database
GRANT CONNECT ON DATABASE hydra_auctions TO hydra_user;
Grant all database privileges
GRANT ALL PRIVILEGES ON DATABASE hydra_auctions TO hydra_user;
Database-level privileges do not automatically grant full access to existing tables.
5. Schema Setup and Permissions
Create a schema
CREATE SCHEMA hydra
AUTHORIZATION hydra_user;
Create a schema only if it does not exist
CREATE SCHEMA IF NOT EXISTS hydra
AUTHORIZATION hydra_user;
Change schema ownership
ALTER SCHEMA public
OWNER TO hydra_user;
Grant access to a schema
GRANT USAGE ON SCHEMA public TO hydra_user;
Allow object creation in a schema
GRANT CREATE ON SCHEMA public TO hydra_user;
Grant access to all existing tables
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA public
TO hydra_user;
Grant access to all existing sequences
Required for SERIAL and identity columns:
GRANT USAGE, SELECT, UPDATE
ON ALL SEQUENCES IN SCHEMA public
TO hydra_user;
Set default privileges for future tables
Run this as the role that will create the tables:
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE
ON TABLES TO hydra_user;
Set default privileges for future sequences
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT, UPDATE
ON SEQUENCES TO hydra_user;
6. Basic Table Creation
Create a simple table
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
email VARCHAR(255),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Create a table only if it does not exist
CREATE TABLE IF NOT EXISTS users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Example auction table
CREATE TABLE auctions (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
scan_id BIGINT NOT NULL,
item_id INTEGER NOT NULL,
name TEXT NOT NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
buyout BIGINT NOT NULL CHECK (buyout >= 0),
faction VARCHAR(20),
scanned_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Create a foreign key
ALTER TABLE auctions
ADD CONSTRAINT auctions_scan_id_fkey
FOREIGN KEY (scan_id)
REFERENCES scans(id)
ON DELETE CASCADE;
Create an index
CREATE INDEX idx_auctions_item_id
ON auctions(item_id);
Create a multi-column index
CREATE INDEX idx_auctions_item_faction
ON auctions(item_id, faction);
Create a unique index
CREATE UNIQUE INDEX idx_users_email_unique
ON users(email);
7. Common Data Commands
Insert a row
INSERT INTO users (username, email)
VALUES ('example_user', 'user@example.com');
Insert multiple rows
INSERT INTO users (username, email)
VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com');
Query all rows
SELECT *
FROM users;
Query selected columns
SELECT id, username, created_at
FROM users;
Filter rows
SELECT *
FROM auctions
WHERE item_id = 818;
Sort results
SELECT *
FROM auctions
ORDER BY scanned_at DESC;
Limit results
SELECT *
FROM auctions
ORDER BY scanned_at DESC
LIMIT 25;
Update rows
UPDATE users
SET email = 'new-address@example.com'
WHERE username = 'example_user';
Delete rows
DELETE FROM users
WHERE username = 'example_user';
Count rows
SELECT COUNT(*)
FROM auctions;
Count rows by value
SELECT faction, COUNT(*)
FROM auctions
GROUP BY faction
ORDER BY COUNT(*) DESC;
8. Modifying Tables
Add a column
ALTER TABLE users
ADD COLUMN last_login TIMESTAMPTZ;
Add a column with a default
ALTER TABLE users
ADD COLUMN active BOOLEAN NOT NULL DEFAULT TRUE;
Rename a column
ALTER TABLE users
RENAME COLUMN username TO account_name;
Change a column data type
ALTER TABLE auctions
ALTER COLUMN buyout TYPE NUMERIC(20, 0);
For complex conversions, use USING:
ALTER TABLE users
ALTER COLUMN id TYPE BIGINT
USING id::BIGINT;
Set a default value
ALTER TABLE users
ALTER COLUMN created_at SET DEFAULT NOW();
Remove a default value
ALTER TABLE users
ALTER COLUMN created_at DROP DEFAULT;
Add a NOT NULL constraint
ALTER TABLE users
ALTER COLUMN email SET NOT NULL;
Before doing this, verify that no existing rows contain NULL.
Remove a NOT NULL constraint
ALTER TABLE users
ALTER COLUMN email DROP NOT NULL;
Add a check constraint
ALTER TABLE auctions
ADD CONSTRAINT auctions_buyout_nonnegative
CHECK (buyout >= 0);
Drop a constraint
ALTER TABLE auctions
DROP CONSTRAINT auctions_buyout_nonnegative;
Rename a table
ALTER TABLE users
RENAME TO application_users;
Change table ownership
ALTER TABLE auctions
OWNER TO hydra_user;
Drop a column
ALTER TABLE users
DROP COLUMN last_login;
Drop a table
DROP TABLE users;
Drop a table only if it exists
DROP TABLE IF EXISTS users;
Drop a table and dependent objects
Use carefully:
DROP TABLE IF EXISTS users CASCADE;
9. Transactions
Transactions allow multiple changes to succeed or fail together.
Start a transaction
BEGIN;
Commit changes
COMMIT;
Undo uncommitted changes
ROLLBACK;
Example safe update
BEGIN;
UPDATE auctions
SET buyout = 0
WHERE item_id = 818;
SELECT *
FROM auctions
WHERE item_id = 818;
COMMIT;
Replace COMMIT with ROLLBACK if the results are incorrect.
10. Inspecting Database Objects
Show table columns using SQL
SELECT
column_name,
data_type,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'auctions'
ORDER BY ordinal_position;
Show table constraints
SELECT
constraint_name,
constraint_type
FROM information_schema.table_constraints
WHERE table_schema = 'public'
AND table_name = 'auctions';
Show indexes for a table
SELECT
indexname,
indexdef
FROM pg_indexes
WHERE schemaname = 'public'
AND tablename = 'auctions';
Show database sizes
SELECT
datname,
pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
ORDER BY pg_database_size(datname) DESC;
Show table sizes
SELECT
schemaname,
relname,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
Show active connections
SELECT
pid,
usename,
datname,
client_addr,
state,
query_start,
query
FROM pg_stat_activity
ORDER BY query_start;
Database Backups
11. Dump the Full Database
A full database dump includes schema definitions and data.
Custom-format backup
Recommended for most backups:
pg_dump \
-h localhost \
-p 5432 \
-U hydra_user \
-d hydra_auctions \
-F c \
-f hydra_auctions.dump
Options:
-F c: custom archive format-f: output file-d: database name-U: PostgreSQL username-h: PostgreSQL host-p: PostgreSQL port
Plain SQL full database backup
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
-F p \
-f hydra_auctions.sql
A plain SQL backup can be viewed in a text editor and restored with psql.
Compressed plain SQL backup
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
| gzip > hydra_auctions.sql.gz
Timestamped backup filename
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
-F c \
-f "hydra_auctions_$(date +%F_%H-%M-%S).dump"
12. Dump Schema Only
A schema-only dump contains tables, sequences, constraints, indexes, functions, and other definitions, but no table data.
Schema-only custom-format dump
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--schema-only \
-F c \
-f hydra_auctions_schema.dump
Schema-only plain SQL dump
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--schema-only \
-f hydra_auctions_schema.sql
Dump one PostgreSQL schema only
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--schema=public \
--schema-only \
-f public_schema.sql
Dump schema without ownership statements
Useful when restoring under a different PostgreSQL user:
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--schema-only \
--no-owner \
--no-privileges \
-f hydra_auctions_schema.sql
13. Dump Data Only
Dump all table data without schema definitions
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--data-only \
-f hydra_auctions_data.sql
Dump data using custom format
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--data-only \
-F c \
-f hydra_auctions_data.dump
14. Dump Specific Tables
Dump one table with schema and data
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--table=auctions \
-f auctions.sql
Dump one table’s data only
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--table=auctions \
--data-only \
-f auctions_data.sql
Dump multiple tables
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--table=scans \
--table=auctions \
-F c \
-f auction_tables.dump
Exclude a table
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--exclude-table=temporary_data \
-F c \
-f hydra_without_temp.dump
Exclude table data but keep its schema
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--exclude-table-data=logs \
-F c \
-f hydra_without_log_data.dump
15. Dump All PostgreSQL Databases
pg_dumpall creates a plain SQL file containing all databases and global objects.
sudo -u postgres pg_dumpall > all_databases.sql
Compressed version:
sudo -u postgres pg_dumpall | gzip > all_databases.sql.gz
Dump only PostgreSQL roles and tablespaces
sudo -u postgres pg_dumpall --globals-only > postgres_globals.sql
This is useful because normal pg_dump backups do not include cluster-wide roles.
Database Restores
16. Restore a Plain SQL Backup
Create the target database first:
sudo -u postgres createdb hydra_auctions
Restore the SQL file:
psql \
-h localhost \
-U hydra_user \
-d hydra_auctions \
-f hydra_auctions.sql
Restore a compressed SQL backup
gunzip -c hydra_auctions.sql.gz \
| psql -h localhost -U hydra_user -d hydra_auctions
17. Restore a Custom-Format Backup
Restore into an existing database
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
hydra_auctions.dump
Drop existing objects before restoring
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--clean \
--if-exists \
hydra_auctions.dump
Restore without original ownership
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--no-owner \
hydra_auctions.dump
Restore and create the database from the dump
The dump must contain database creation metadata:
pg_restore \
-h localhost \
-U postgres \
--create \
-d postgres \
hydra_auctions.dump
Restore only the schema
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--schema-only \
hydra_auctions.dump
Restore only the data
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--data-only \
hydra_auctions.dump
List backup contents
pg_restore --list hydra_auctions.dump
Restore in parallel
Custom and directory formats support parallel restore:
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--jobs=4 \
hydra_auctions.dump
18. Restore All Databases and Roles
sudo -u postgres psql -f all_databases.sql
For a compressed dump:
gunzip -c all_databases.sql.gz \
| sudo -u postgres psql
19. Recreate a Database Before Restore
Terminate existing connections:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'hydra_auctions'
AND pid <> pg_backend_pid();
Drop and recreate the database:
sudo -u postgres dropdb hydra_auctions
sudo -u postgres createdb -O hydra_user hydra_auctions
Restore:
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--no-owner \
hydra_auctions.dump
Docker PostgreSQL
20. Basic Docker Compose PostgreSQL Service
services:
db:
image: postgres:16
container_name: hydra-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- hydra_postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
hydra_postgres_data:
Example .env file:
POSTGRES_DB=hydra_auctions
POSTGRES_USER=hydra_user
POSTGRES_PASSWORD=replace-with-secure-password
The final volumes: section declares the named volume. Docker creates and manages the actual storage location.
21. Start and Inspect the Container
docker compose up -d
docker compose ps
docker compose logs db
docker compose logs -f db
docker inspect hydra-postgres
22. Connect to PostgreSQL Inside Docker
docker exec -it hydra-postgres \
psql -U hydra_user -d hydra_auctions
Using Docker Compose:
docker compose exec db \
psql -U hydra_user -d hydra_auctions
23. Back Up a Docker PostgreSQL Database
Custom-format backup to the host
docker exec hydra-postgres \
pg_dump -U hydra_user -d hydra_auctions -F c \
> hydra_auctions.dump
Plain SQL backup to the host
docker exec hydra-postgres \
pg_dump -U hydra_user -d hydra_auctions \
> hydra_auctions.sql
Schema-only Docker backup
docker exec hydra-postgres \
pg_dump -U hydra_user -d hydra_auctions --schema-only \
> hydra_auctions_schema.sql
Data-only Docker backup
docker exec hydra-postgres \
pg_dump -U hydra_user -d hydra_auctions --data-only \
> hydra_auctions_data.sql
Timestamped Docker backup
docker exec hydra-postgres \
pg_dump -U hydra_user -d hydra_auctions -F c \
> "hydra_auctions_$(date +%F_%H-%M-%S).dump"
24. Restore a Docker PostgreSQL Database
Restore a plain SQL file
cat hydra_auctions.sql \
| docker exec -i hydra-postgres \
psql -U hydra_user -d hydra_auctions
Restore a custom-format dump
Copy the dump into the container:
docker cp hydra_auctions.dump \
hydra-postgres:/tmp/hydra_auctions.dump
Restore it:
docker exec -it hydra-postgres \
pg_restore \
-U hydra_user \
-d hydra_auctions \
--clean \
--if-exists \
--no-owner \
/tmp/hydra_auctions.dump
Remove the copied dump:
docker exec hydra-postgres \
rm /tmp/hydra_auctions.dump
Restore through standard input
docker exec -i hydra-postgres \
pg_restore \
-U hydra_user \
-d hydra_auctions \
--no-owner \
< hydra_auctions.dump
25. PostgreSQL Initialization Scripts in Docker
SQL and shell files placed in /docker-entrypoint-initdb.d/ run only when the PostgreSQL data directory is first initialized.
Example Compose mount:
services:
db:
image: postgres:16
volumes:
- hydra_postgres_data:/var/lib/postgresql/data
- ./database/init:/docker-entrypoint-initdb.d:ro
Example project structure:
database/
└── init/
├── 01-schema.sql
└── 02-seed-data.sql
Important:
- Initialization scripts do not run again when an existing named volume is reused.
- Removing the volume deletes the database data.
- Use migrations such as Alembic for ongoing schema changes.
Remove containers and the database volume:
docker compose down -v
This permanently deletes the database stored in the Compose volume.
PostgreSQL Authentication and Configuration
26. Find PostgreSQL Configuration Files
From psql:
SHOW config_file;
SHOW hba_file;
SHOW data_directory;
Common files:
postgresql.conf
pg_hba.conf
pg_ident.conf
27. Allow Password Authentication
Example pg_hba.conf entries:
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
For a trusted private network:
host hydra_auctions hydra_user 192.168.1.0/24 scram-sha-256
Reload PostgreSQL after changing pg_hba.conf:
sudo systemctl reload postgresql
or from SQL:
SELECT pg_reload_conf();
28. Listen on Network Interfaces
In postgresql.conf:
listen_addresses = '*'
port = 5432
Restart PostgreSQL:
sudo systemctl restart postgresql
Open the firewall only for required sources:
sudo firewall-cmd \
--permanent \
--add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="5432" accept'
sudo firewall-cmd --reload
Do not expose PostgreSQL directly to the public internet unless it is protected by strong network controls.
Password Handling
29. Use a .pgpass File
Create:
nano ~/.pgpass
Format:
hostname:port:database:username:password
Example:
localhost:5432:hydra_auctions:hydra_user:replace-with-password
Set required permissions:
chmod 600 ~/.pgpass
Then run commands without an interactive password prompt:
pg_dump -h localhost -U hydra_user -d hydra_auctions -F c -f backup.dump
30. Use PGPASSWORD Temporarily
PGPASSWORD='replace-with-password' \
pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
-F c \
-f hydra_auctions.dump
This can expose the password to process inspection or shell history. Prefer .pgpass, Docker secrets, or another secrets manager.
Backup Automation
31. Simple Backup Script
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/postgresql"
DATABASE="hydra_auctions"
USER_NAME="hydra_user"
HOST_NAME="localhost"
RETENTION_DAYS=14
TIMESTAMP="$(date +%F_%H-%M-%S)"
BACKUP_FILE="${BACKUP_DIR}/${DATABASE}_${TIMESTAMP}.dump"
mkdir -p "$BACKUP_DIR"
pg_dump \
-h "$HOST_NAME" \
-U "$USER_NAME" \
-d "$DATABASE" \
-F c \
-f "$BACKUP_FILE"
find "$BACKUP_DIR" \
-type f \
-name "${DATABASE}_*.dump" \
-mtime +"$RETENTION_DAYS" \
-delete
echo "Backup completed: $BACKUP_FILE"
Make it executable:
chmod +x /usr/local/sbin/backup-hydra-postgres.sh
Run it:
/usr/local/sbin/backup-hydra-postgres.sh
32. Cron Backup Example
Edit the current user’s crontab:
crontab -e
Run every day at 2:00 AM:
0 2 * * * /usr/local/sbin/backup-hydra-postgres.sh >> /var/log/hydra-postgres-backup.log 2>&1
33. systemd Service and Timer
Service file:
# /etc/systemd/system/hydra-postgres-backup.service
[Unit]
Description=Back up Hydra PostgreSQL database
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup-hydra-postgres.sh
Timer file:
# /etc/systemd/system/hydra-postgres-backup.timer
[Unit]
Description=Run Hydra PostgreSQL backup daily
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
Enable the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now hydra-postgres-backup.timer
Check the timer:
systemctl list-timers hydra-postgres-backup.timer
Run the backup manually:
sudo systemctl start hydra-postgres-backup.service
View logs:
journalctl -u hydra-postgres-backup.service
Maintenance and Troubleshooting
34. Analyze and Vacuum
Update query planner statistics:
ANALYZE;
Vacuum all tables in the current database:
VACUUM;
Vacuum and analyze:
VACUUM ANALYZE;
Reclaim more disk space with an exclusive lock:
VACUUM FULL;
Use VACUUM FULL carefully because it locks and rewrites tables.
Run from the shell
vacuumdb \
-h localhost \
-U hydra_user \
-d hydra_auctions \
--analyze
35. Reindex
Reindex one table:
REINDEX TABLE auctions;
Reindex a database:
REINDEX DATABASE hydra_auctions;
36. Check Long-Running Queries
SELECT
pid,
now() - query_start AS duration,
usename,
datname,
state,
query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY duration DESC;
Cancel a query:
SELECT pg_cancel_backend(12345);
Terminate a connection:
SELECT pg_terminate_backend(12345);
37. Check Locks
SELECT
locktype,
database,
relation::regclass,
mode,
granted,
pid
FROM pg_locks
ORDER BY granted, pid;
38. Common Error: Peer Authentication Failed
Example error:
FATAL: Peer authentication failed for user "postgres"
Use the operating-system postgres account:
sudo -u postgres psql
Or connect using TCP and password authentication:
psql -h localhost -U postgres -d postgres -W
The authentication behavior is controlled by pg_hba.conf.
39. Common Error: Server and Client Version Mismatch
Example:
pg_dump: error: server version: 16.x
pg_dump version: 13.x
Use a pg_dump version that is the same major version as the server or newer.
Check versions:
pg_dump --version
SELECT version();
On RHEL-based systems, install the matching PostgreSQL client package or use the pg_dump binary from the matching PostgreSQL installation.
Example path:
/usr/pgsql-16/bin/pg_dump --version
Example backup:
/usr/pgsql-16/bin/pg_dump \
-h localhost \
-U hydra_user \
-d hydra_auctions \
-F c \
-f hydra_auctions.dump
40. Common Error: Could Not Change Directory
Example:
could not change directory to "/root": Permission denied
This commonly happens when using:
sudo -u postgres ...
from a directory the postgres operating-system user cannot access.
Change to a readable directory first:
cd /tmp
sudo -u postgres pg_dump hydra_auctions > /tmp/hydra_auctions.sql
Or write the backup to a directory owned by postgres.
Roles and Security
41. Role Management
Create a read-only role
CREATE ROLE hydra_readonly;
GRANT CONNECT ON DATABASE hydra_auctions TO hydra_readonly;
GRANT USAGE ON SCHEMA public TO hydra_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO hydra_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO hydra_readonly;
Assign the role to a user
GRANT hydra_readonly TO reporting_user;
Remove a role from a user
REVOKE hydra_readonly FROM reporting_user;
Remove login access
ALTER ROLE hydra_user NOLOGIN;
Restore login access
ALTER ROLE hydra_user LOGIN;
Drop a user or role
DROP ROLE hydra_user;
Before dropping a role, ownership and privileges may need to be reassigned:
REASSIGN OWNED BY hydra_user TO postgres;
DROP OWNED BY hydra_user;
DROP ROLE hydra_user;
Migration Workflow
42. Recommended Schema Change Workflow
- Back up the database.
- Test the change against a development or staging database.
- Put changes in a migration file.
- Run the migration inside a transaction when possible.
- Verify the schema and application behavior.
- Keep the migration file in source control.
Example SQL migration:
BEGIN;
ALTER TABLE auctions
ADD COLUMN source VARCHAR(50);
CREATE INDEX idx_auctions_source
ON auctions(source);
COMMIT;
Rollback migration:
BEGIN;
DROP INDEX IF EXISTS idx_auctions_source;
ALTER TABLE auctions
DROP COLUMN IF EXISTS source;
COMMIT;
For Python applications using SQLAlchemy, Alembic is commonly used to track and apply schema migrations.
Quick Reference
43. Frequently Used Commands
Connect locally
sudo -u postgres psql
List databases
\l
List users
\du
List tables
\dt
Describe a table
\d+ auctions
Full database dump
pg_dump -h localhost -U hydra_user -d hydra_auctions -F c -f hydra_auctions.dump
Schema-only dump
pg_dump -h localhost -U hydra_user -d hydra_auctions --schema-only -f hydra_schema.sql
Data-only dump
pg_dump -h localhost -U hydra_user -d hydra_auctions --data-only -f hydra_data.sql
Restore custom dump
pg_restore -h localhost -U hydra_user -d hydra_auctions --no-owner hydra_auctions.dump
Restore plain SQL
psql -h localhost -U hydra_user -d hydra_auctions -f hydra_auctions.sql
Docker full database dump
docker exec hydra-postgres pg_dump -U hydra_user -d hydra_auctions -F c > hydra_auctions.dump
Docker schema dump
docker exec hydra-postgres pg_dump -U hydra_user -d hydra_auctions --schema-only > hydra_schema.sql
Docker restore
docker exec -i hydra-postgres pg_restore -U hydra_user -d hydra_auctions --no-owner < hydra_auctions.dump
Backup Checklist
Before relying on a backup:
- Confirm the backup command completed successfully.
- Confirm the backup file is not empty.
- Store copies outside the PostgreSQL server or Docker host.
- Encrypt backups containing sensitive information.
- Test restores regularly.
- Keep PostgreSQL role backups when needed.
- Keep multiple generations of backups.
- Document the PostgreSQL major version used to create each backup.
Check file size:
ls -lh hydra_auctions.dump
Inspect a custom backup:
pg_restore --list hydra_auctions.dump | head
Test a restore into a temporary database:
createdb -h localhost -U hydra_user hydra_restore_test
pg_restore \
-h localhost \
-U hydra_user \
-d hydra_restore_test \
--no-owner \
hydra_auctions.dump
Delete the test database:
dropdb -h localhost -U hydra_user hydra_restore_test