To host PostgreSQL database workloads successfully, you need more than a running server. You need controlled network access, strong authentication, encrypted connections, tested backups, and clear monitoring.
Development can run on your laptop with local defaults. Production needs private networking, restricted roles, recovery procedures, update planning, and connection limits. The correct setup depends on your traffic, team, compliance needs, and tolerance for database maintenance.
Start with the hosting model, then configure PostgreSQL in the same order that applications use it: storage, networking, authentication, encryption, connections, backups, and monitoring.
Choose Where to Host PostgreSQL Database Workloads
You have three practical options:
| Hosting model | Good fit | Main responsibility |
|---|---|---|
| Local development | Prototyping and tests | Developer |
| Self-hosted server | Teams needing OS and database control | Your team |
| Managed PostgreSQL | Teams that want less infrastructure work | Provider and your team |
A local installation is enough for development. Docker is also useful when every developer needs the same PostgreSQL version and extensions.
Self-hosting gives you direct access to the operating system, PostgreSQL configuration, storage, logs, and network rules. You also own patching, disk alerts, backups, failover, certificate renewal, and recovery testing.
A managed PostgreSQL service can handle parts of that work. Read the service documentation before planning your architecture. Providers may control postgresql.conf, pg_hba.conf, TLS certificates, replication, maintenance windows, or backup settings.
Kubernetes teams should also check how their operator manages PostgreSQL configuration. For example, CloudNativePG’s configuration reference documents operator-managed settings for PostgreSQL clusters.
Plan Storage, Roles, and Environments First
Create separate development, staging, and production databases. Don’t point a local application at production because it is convenient.
Use a separate database and role for each application where practical. A web application doesn’t need PostgreSQL superuser access. Migration tools may need schema permissions, but the runtime application usually needs fewer rights.
A basic local setup can use the default PostgreSQL port, 5432, and a database named appdb.
CREATE ROLE app_user LOGIN;
CREATE DATABASE appdb OWNER app_user;
\password app_user
Run the password command inside psql. Don’t place a real password in a script committed to source control.
For production, plan storage before deployment. Database size is only part of the requirement. Add room for indexes, temporary files, table growth, write-ahead logs, backups, and maintenance operations.
Use fast persistent storage for production workloads. Monitor free space and inode usage. A full disk can stop writes, prevent WAL creation, and make recovery harder.
Install PostgreSQL for Development
Installation steps depend on the operating system. Use the package source recommended for your operating system and select a supported PostgreSQL major version.
On a Debian or Ubuntu development machine, a basic package installation often looks like this:
sudo apt update
sudo apt install postgresql postgresql-contrib
sudo systemctl enable --now postgresql
Confirm that the server is running:
sudo systemctl status postgresql
pg_isready -h 127.0.0.1 -p 5432
The pg_isready utility checks whether PostgreSQL accepts connections. Keep it for local health checks and production liveness checks. The official pg_isready documentation is available through the PostgreSQL documentation index.
Connect through the local operating-system account or a configured database role:
sudo -u postgres psql
Then inspect the active configuration paths:
SHOW data_directory;
SHOW config_file;
SHOW hba_file;
SHOW listen_addresses;
SHOW port;
These commands prevent a common mistake: editing a configuration file that the running server doesn’t use.
Configure PostgreSQL Networking
PostgreSQL listens only on the interfaces defined by listen_addresses. The default is usually localhost, which allows local connections but blocks remote TCP connections.
For a development machine, keep the local default:
listen_addresses = 'localhost'
port = 5432
You can also set listen_addresses to an empty value when you want Unix-domain socket connections only. That removes TCP/IP listening and works for local applications that support PostgreSQL sockets.
Production usually needs a private network address. You can bind to a specific private IP:
listen_addresses = '10.20.0.15'
Using * makes PostgreSQL listen on all available interfaces. That can work with strict firewall rules, but it increases the chance of exposing the service by mistake.
The setting takes effect after a server restart, not only a configuration reload:
sudo systemctl restart postgresql
Open port 5432 only to the application network or approved administration network. Don’t expose it to the entire internet when a private subnet, VPN, bastion host, or provider-internal network is available.
listen_addresses controls reachability. It doesn’t authenticate users. The firewall controls who can reach the port, and pg_hba.conf controls which connections PostgreSQL accepts after they arrive.
Configure Authentication with pg_hba.conf
The pg_hba.conf file contains host-based authentication rules. PostgreSQL checks the rules from top to bottom and uses the first matching record.
Start with narrow rules. A development configuration might include:
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
The peer method checks the operating-system username for local socket connections. The scram-sha-256 method uses password authentication with a modern password verifier.
For production, separate application access from administration and replication. A rule might look like this:
hostssl appdb app_user 10.20.0.0/16 scram-sha-256
This permits app_user to access appdb from the stated private CIDR range over an encrypted connection.
Avoid broad rules such as:
host all all 0.0.0.0/0 trust
The trust method allows a matching client to connect without a password. It is unsuitable for production access.
A host rule can match encrypted and unencrypted TCP connections. A hostssl rule requires SSL/TLS. Review the PostgreSQL pg_hba.conf documentation before changing rule order or authentication methods.
Reload authentication changes without restarting the whole server:
SELECT pg_reload_conf();
Test with the same hostname, role, database, and SSL mode that your application uses.
Enable SSL/TLS for Production Connections
Encryption protects credentials and application data while they move between the client and PostgreSQL. Production remote connections should use TLS.
A self-hosted server needs a certificate and private key. A simplified server configuration looks like this:
ssl = on
ssl_cert_file = '/etc/postgresql/18/main/server.crt'
ssl_key_file = '/etc/postgresql/18/main/server.key'
Protect the private key with restrictive file permissions. The PostgreSQL service account must be able to read it, while unrelated users must not.
The ssl setting is a server-start setting. Restart PostgreSQL after changing it:
sudo systemctl restart postgresql
Then require TLS in pg_hba.conf:
hostssl appdb app_user 10.20.0.0/16 scram-sha-256
Use a trusted certificate authority for production clients. sslmode=require encrypts the connection, but it doesn’t provide full server identity verification. For stronger verification, use sslmode=verify-full with the correct CA certificate and hostname.
Managed services may provide a CA bundle and a provider-specific endpoint. For example, AWS documents SSL connection behavior for Amazon RDS for PostgreSQL. Treat that as provider-specific guidance, not a universal configuration for every host.
A connection can be reachable and authenticated while still being unencrypted. Use
hostsslwhen production access must require TLS.
Build Safe PostgreSQL Connection Strings
Applications need the host, port, database, username, password source, and SSL settings. Use explicit values in production.
A local Unix-socket connection can omit the host:
psql "dbname=appdb user=app_user"
A local TCP connection uses the loopback address:
psql "host=127.0.0.1 port=5432 dbname=appdb user=app_user"
A production connection can require encryption:
psql "host=db.internal.example port=5432 dbname=appdb user=app_user sslmode=require"
For certificate verification:
psql "host=db.internal.example port=5432 dbname=appdb user=app_user sslmode=verify-full sslrootcert=/run/secrets/postgres-ca.crt"
Don’t put database passwords directly in shell commands. Shell history, process inspection, CI logs, and error reports can expose them.
Use a secrets manager, environment variables supplied by the deployment platform, or a protected .pgpass file. A .pgpass file must have restrictive permissions:
chmod 600 ~/.pgpass
A connection URI is convenient for application configuration:
postgresql://app_user:REDACTED@db.internal.example:5432/appdb?sslmode=verify-full
URL-encode special characters in usernames and passwords when they appear inside a URI. Many frameworks also support separate variables such as PGHOST, PGPORT, PGDATABASE, PGUSER, and PGSSLMODE.
Keep connection pooling in mind. Every application process can consume a database connection. Set pool limits so a deployment cannot exhaust PostgreSQL before it serves requests.
Back Up PostgreSQL and Test Recovery
A backup is useful only when you can restore it. Test recovery on a separate database or server.
Use pg_dump for a logical backup of one database:
pg_dump -Fc -d appdb -f /var/backups/postgresql/appdb.dump
The custom format works with pg_restore and is usually more flexible than a plain SQL file.
Restore it into a separate database:
createdb appdb_restore
pg_restore --no-owner -d appdb_restore /var/backups/postgresql/appdb.dump
Check tables, row counts, extensions, roles, and application behavior after restoration. Keep the original production database untouched during a restore test.
A logical dump is not the same as continuous recovery. pg_dump doesn’t provide point-in-time recovery from WAL files. Production systems that need recovery after an accidental deletion or server failure need base backups and WAL archiving.
The main PostgreSQL settings for WAL archiving include:
wal_level = replica
archive_mode = on
archive_command = 'your-approved-archive-command'
The archive destination must be separate from the primary database disk. A second directory on the same failed disk isn’t a reliable disaster-recovery location.
Use regular logical dumps for portability and selective restores. Use base backups plus WAL archiving when your recovery plan requires a specific point in time. The PostgreSQL backup and restore documentation index links to the current backup chapters and utilities.
Record these backup controls:
- Backup schedule and retention period.
- Storage location and encryption status.
- Last successful backup.
- Last successful restore test.
- Recovery point objective and recovery time objective.
- Person responsible for responding to a failed backup.
Plan PostgreSQL Updates and Version Changes
PostgreSQL has separate minor updates and major version upgrades. Treat both as planned operational work.
As of September 2026, the current PostgreSQL documentation lists versions 18, 17, 16, 15, and 14 as supported. Check the live PostgreSQL release information before selecting a version for a new system.
Before an update:
- Take a fresh backup.
- Confirm that the backup can be read.
- Review extension compatibility.
- Test the update in staging.
- Confirm the restart and rollback plan.
- Check application connection settings.
- Apply the change during a defined maintenance window.
- Verify authentication, TLS, migrations, and monitoring afterward.
A major version upgrade can require pg_upgrade, logical replication, a provider migration, or a dump-and-restore process. The correct method depends on database size, downtime limits, extensions, and hosting model.
Don’t copy a production data directory between major versions without following the supported upgrade process.
Managed services often apply minor updates according to a maintenance schedule. You still need to verify application compatibility and connection behavior. A provider may also restrict superuser operations or extension installation.
Monitor Connections, Storage, and Query Activity
Monitoring should detect failures before application users report them.
Start with a liveness check:
pg_isready -h db.internal.example -p 5432 -d appdb
Check active sessions with pg_stat_activity:
SELECT pid,
usename,
application_name,
client_addr,
state,
wait_event_type,
query_start,
left(query, 120) AS query
FROM pg_stat_activity
WHERE datname = current_database()
ORDER BY query_start;
Track connection count and compare it with the configured limit:
SELECT count(*) AS current_connections
FROM pg_stat_activity;
SHOW max_connections;
Monitor disk usage outside PostgreSQL as well as database-level statistics. Alert on low storage, failed backups, long-running transactions, connection saturation, replication lag, WAL archive failures, and repeated authentication errors.
For replication and WAL archiving, inspect the relevant statistics views:
SELECT * FROM pg_stat_replication;
SELECT * FROM pg_stat_archiver;
A health check that only confirms port 5432 is open is incomplete. The server might be reachable while authentication is failing, WAL archiving is broken, or the database is out of storage.
The PostgreSQL monitoring documentation covers the statistics views and monitoring functions used for deeper checks.
Separate Development Defaults from Production Controls
Development should be easy to reset. Production should be difficult to misuse.
| Area | Development | Production |
|---|---|---|
| Network | localhost or Unix socket | Private interface and restricted firewall |
| Authentication | Local peer or password | Narrow pg_hba.conf rules with SCRAM |
| TLS | Optional for local-only access | Required for remote access |
| Backups | Periodic pg_dump | Logical backups plus recovery-capable backups |
| Updates | Frequent testing | Staged change with rollback plan |
| Monitoring | Basic readiness check | Alerts for storage, sessions, backups, and replication |
| Credentials | Local secrets file | Managed secret with rotation |
| Roles | Convenience roles | Least-privilege application roles |
Don’t copy development files into production without reviewing every setting. A local listen_addresses value may block the application. A permissive pg_hba.conf rule may expose the database. A local backup directory may disappear with the server.
For a production deployment, verify the complete path:
- The firewall permits only approved sources.
- PostgreSQL listens on the intended private interface.
- The database and role exist.
pg_hba.confmatches the application network.- TLS is enabled and the certificate is valid.
- The connection string uses the expected hostname and SSL mode.
- A backup completes.
- A restore test succeeds.
- Monitoring reports healthy status.
- The team knows who responds when the database fails.
Common Hosting Mistakes to Avoid
The most common mistake is treating a running PostgreSQL process as a production deployment. Process status doesn’t prove safe access, recoverable data, or correct application permissions.
Avoid these failures:
- Exposing port
5432to the public internet. - Using
trustauthentication for application access. - Giving the web application a superuser role.
- Using
hostrules when all remote access should require TLS. - Storing passwords in Git, shell history, or container images.
- Keeping backups on the same disk as the database.
- Assuming a successful
pg_dumpproves point-in-time recovery. - Updating the major version without testing extensions.
- Allowing unlimited application connections.
- Overwriting backup files without retention or restore checks.
- Ignoring certificate expiration dates.
- Treating a provider’s automated backup as a complete disaster-recovery plan without checking retention and restore scope.
Document the settings that matter. Store the PostgreSQL version, endpoint, port, database names, roles, extensions, backup policy, restore procedure, certificate source, and maintenance process in an access-controlled location.
Conclusion
To host PostgreSQL database workloads safely, build the deployment around controlled access and proven recovery. Keep development local and simple. Use private networking, SCRAM authentication, TLS, least-privilege roles, tested backups, and monitoring in production.
The strongest setup is not the one with the most configuration. It is the one your team can explain, update, restore, and troubleshoot under pressure. Start with one verified connection, then test the full path from application request to backup recovery.
