Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

PostgreSQL Administration Essentials

By Kokil Thapa | Last reviewed: September 2026

PostgreSQL Administration Essentials is the set of daily tasks that keep a database alive after launch: install, secure, back up, tune, monitor, and recover. Most teams pick PostgreSQL for JSON support, strict SQL, and predictable concurrency. Then they treat it like a black box until disk fills or queries crawl. I've maintained PostgreSQL on production Laravel applications and booking systems where downtime means lost orders. This guide walks through the admin work I actually do on Ubuntu servers—not theory from a certification slide deck.

What does PostgreSQL administration cover for production web apps?

Administration sits between application code and the operating system. Your Laravel or Symfony app talks through a connection pool. PostgreSQL handles rows, locks, and WAL files on disk. The Linux host supplies CPU, RAM, and I/O.

A production admin stack has six layers. Skip any one and you will feel it during Dashain traffic spikes or a failed deploy.

  • Installation and access control — correct version, limited network exposure, role-based grants
  • Backup and recovery — pg_dump schedules plus WAL archiving for point-in-time restore
  • Performance tuning — shared_buffers, work_mem, indexes, and autovacuum settings
  • Monitoring — connection counts, slow queries, disk growth, replication lag
  • Maintenance — vacuum, reindex, extension updates, major version upgrades
  • Security — TLS, pg_hba.conf rules, least-privilege app users, audit logging

If you are choosing between engines, read PostgreSQL vs MySQL for production first. PostgreSQL rewards teams that plan maintenance windows. MySQL often feels simpler on shared hosting. Both fail the same way when nobody owns backups.

PostgreSQL Admin StackLaravel / API Application LayerConnection Pool + App DB UserPostgreSQL 18 ServerWAL, vacuum, indexes, extensionsUbuntu 24 + Disk + Backupspg_dump cron, monitoring, TLS
PostgreSQL Administration Essentials spans the full stack from application queries down to OS-level backup and monitoring.

On booking platforms like Adventure Third Pole Trek, the database holds itineraries, payments, and supplier records. Admin work is not optional. It is part of shipping reliable software.

How do you install and configure PostgreSQL 18 on Ubuntu?

Ubuntu 24.04 ships PostgreSQL packages from the PGDG apt repository. Pin the major version you want. PostgreSQL 18 is current. PostgreSQL 17 remains common on managed hosts. Do not mix versions across app servers and replicas.

Add the official PostgreSQL apt repository

sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt update
sudo apt install -y postgresql-18 postgresql-client-18

Confirm the cluster status:

sudo systemctl status postgresql
sudo -u postgres psql -c "SELECT version();"

Create application roles with least privilege

Never point Laravel at the postgres superuser. Create a database, an owner role, and a separate migration role if you use schema-only deploys.

sudo -u postgres psql <<'SQL'
CREATE ROLE app_owner LOGIN PASSWORD 'replace-with-strong-secret';
CREATE ROLE app_user LOGIN PASSWORD 'replace-with-strong-secret';
CREATE DATABASE myapp_db OWNER app_owner ENCODING 'UTF8';
GRANT CONNECT ON DATABASE myapp_db TO app_user;
SQL

Inside the database, grant schema usage explicitly:

sudo -u postgres psql -d myapp_db -c "GRANT USAGE ON SCHEMA public TO app_user;"
sudo -u postgres psql -d myapp_db -c "GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;"

Lock down pg_hba.conf and listen_addresses

Edit /etc/postgresql/18/main/postgresql.conf and set listen_addresses to the private interface IP—not * on a public VPS. Then restrict clients in pg_hba.conf:

# TYPE  DATABASE   USER      ADDRESS           METHOD
host    myapp_db   app_user  10.0.1.0/24       scram-sha-256
hostssl myapp_db   app_user  10.0.1.0/24       scram-sha-256

Reload after changes:

sudo systemctl reload postgresql

For full server hardening beyond the database, see Linux system administration practices. Firewall rules with UFW should allow port 5432 only from app subnets.

SettingDev defaultProduction starting pointWhy it matters
listen_addresseslocalhostPrivate IP onlyStops random internet scans hitting 5432
ssloff locallyon with valid certEncrypts credentials and row data in transit
log_min_duration_statement-1 (off)500–1000 msSurfaces slow queries without log floods
max_connections100100–200 + poolerLaravel opens many idle connections under load
shared_buffers128 MB25% of RAM (cap ~8 GB)Primary page cache for hot data

Official install docs live at postgresql.org/download/linux/ubuntu. Cross-check package names before you paste commands into CI.

How do you back up and restore PostgreSQL databases safely?

Backups are the heart of PostgreSQL Administration Essentials. A logical dump via pg_dump is simple. Physical base backups plus WAL archiving give you point-in-time recovery. You need both skills.

Schedule logical dumps with pg_dump

For small and mid-size Laravel apps under roughly 50 GB, nightly custom-format dumps work well. Store them off-server.

#!/bin/bash
BACKUP_DIR="/var/backups/postgresql"
STAMP=$(date +%Y%m%d_%H%M)
mkdir -p "$BACKUP_DIR"
pg_dump -Fc -U app_owner -d myapp_db -f "$BACKUP_DIR/myapp_db_$STAMP.dump"
find "$BACKUP_DIR" -name "*.dump" -mtime +14 -delete

Test restores monthly on a staging VM. A backup you have never restored is a guess.

pg_restore -C -d postgres /var/backups/postgresql/myapp_db_20260909_0200.dump

Enable WAL archiving for point-in-time recovery

When you need to rewind to 14:07 before a bad migration, WAL files are the only path. Enable archiving in postgresql.conf:

archive_mode = on
archive_command = 'test ! -f /mnt/wal_archive/%f && cp %p /mnt/wal_archive/%f'
wal_level = replica

Take a base backup with pg_basebackup:

pg_basebackup -D /var/lib/postgresql/18/base_backups/$(date +%F) \
  -Ft -z -P -U replication_user -h localhost

Our detailed PostgreSQL point-in-time recovery playbook walks through full restore steps. Read it before your first incident, not during one.

Backup and Recovery FlowLive DBPostgreSQL 18pg_dumpNightly logicalOff-site StoreS3 or rsyncWAL ArchiveContinuousPITR RestoreTarget timestampRecovered DBStaging firstMonthly restore drillVerify dump integrity before you need it
PostgreSQL Administration Essentials requires both scheduled pg_dump backups and WAL archiving for point-in-time recovery.

If you are moving from MySQL, plan the cutover with our MySQL to PostgreSQL migration guide. Dump-and-restore timing affects downtime windows.

How do you tune PostgreSQL performance for Laravel and API workloads?

Most Laravel slowness is N+1 queries or missing indexes—not mysterious PostgreSQL bugs. Still, baseline server tuning prevents pain as tables grow.

Memory settings that actually move the needle

On a 8 GB RAM VPS running only PostgreSQL:

shared_buffers = 2GB
effective_cache_size = 6GB
work_mem = 16MB
maintenance_work_mem = 512MB
random_page_cost = 1.1    # for SSD/NVMe

Restart PostgreSQL after changing shared_buffers. Reload is enough for most other knobs.

Autovacuum and bloat

PostgreSQL uses MVCC. Dead row versions pile up without vacuum. Heavy write tables—carts, audit logs, notification queues—need aggressive autovacuum.

ALTER TABLE orders SET (
  autovacuum_vacuum_scale_factor = 0.05,
  autovacuum_analyze_scale_factor = 0.02
);

Check bloat with pg_stat_user_tables:

SELECT relname, n_live_tup, n_dead_tup,
       round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 15;

Indexes and EXPLAIN

Run EXPLAIN (ANALYZE, BUFFERS) on slow Eloquent queries. Partial indexes help soft-deleted models:

CREATE INDEX idx_orders_open ON orders (created_at)
WHERE deleted_at IS NULL;

For JSON columns, GIN indexes beat sequential scans. Compare patterns in MySQL 8 vs PostgreSQL for web apps if your team is split across engines.

Performance Tuning LayersApplication Query DesignEloquent eager load, paginationIndexes + EXPLAIN ANALYZEB-tree, GIN, partial indexesMemory Configshared_buffers, work_memAutovacuum + Disk I/ODead tuples, SSD random_page_cost
Tune PostgreSQL from the query layer down—fix Laravel N+1 problems before you chase exotic server parameters.

Redis 8.10 for cache and session storage offloads read pressure. PostgreSQL should not cache what Redis handles better. On eCommerce projects like Quick And Easy Nepalese Grocery, delivery-zone lookups need indexed postcode columns—not full table scans at checkout.

How do you monitor PostgreSQL and handle common production problems?

Monitoring turns admin from reactive firefighting into scheduled work. You need metrics, logs, and alert thresholds.

Essential queries every admin should bookmark

Active connections and idle clients:

SELECT state, count(*) FROM pg_stat_activity GROUP BY state;

Long-running queries:

SELECT pid, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active' AND query_start < now() - interval '30 seconds';

Table and index size:

SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

Export these to Grafana via postgres_exporter, or run them from a cron script that emails on threshold breach. For replication setups, see PostgreSQL replication and high availability.

Common failures and fixes

  1. Disk full on WAL volume — expand disk, then run SELECT pg_switch_wal(); and verify archiving resumes
  2. Too many connections — add PgBouncer in transaction pooling mode; lower Laravel DB_PERSISTENT misuse
  3. Lock waits on deploy — use lock_timeout in migration sessions; schedule DDL off-peak
  4. Sequence exhaustion on bigserial — rare but real; monitor pg_sequences on high-insert tables
  5. Permission denied after restore — re-run grants; pg_dump -Fc with --no-owner needs explicit role mapping

Terminal skills from essential Ubuntu terminal commands help during SSH sessions at 2 AM. Keep a runbook doc next to the server IP list.

Production TroubleshootingApp DB Error?ConnectionsCheck pg_stat_activitySlow QueriesEXPLAIN + indexesAdd PgBouncerPool idle clientsTune vacuumFix bloat tablesAlways check disk + WAL first
When PostgreSQL fails in production, split connection errors from slow-query problems before you change config at random.

Structured logs help API teams debug JSON payloads. Paste sanitized query output through a JSON formatter before sharing in tickets. For ongoing DBA work you cannot staff in-house, support and maintenance covers backup verification and upgrade planning.

Enterprise apps with strict uptime targets should pair monitoring with HA architecture. Enterprise application development projects I have shipped treat the database as a first-class component—not an afterthought behind PHP code.

The official monitoring chapter in the PostgreSQL documentation lists every pg_stat_* view. Bookmark it. pg_dump reference documents format flags that matter for large restores.

If your stack also runs document stores, compare routines with MongoDB administration basics. Different engine, same discipline: backups, monitoring, rehearsed recovery.

Key Takeaways

  • Install PostgreSQL 18 with scoped roles, pg_hba.conf restrictions, and TLS before you point production Laravel traffic at it.
  • Automate pg_dump nightly and enable WAL archiving if you need point-in-time recovery—then prove restores work on staging.
  • Tune shared_buffers and autovacuum first; fix application N+1 queries and missing indexes before chasing exotic parameters.
  • Monitor connections, dead tuples, disk usage, and slow queries with pg_stat views or postgres_exporter alerts.
  • Keep a troubleshooting runbook for disk-full WAL, connection exhaustion, and migration lock waits.
  • Rehearse major version upgrades on a clone; PostgreSQL 17 to 18 jumps need extension compatibility checks.

People Also Ask

Is PostgreSQL hard to administer compared to MySQL?

PostgreSQL asks for more upfront tuning and vacuum awareness. MySQL feels simpler on cPanel-style hosting. PostgreSQL gives you stricter SQL, better concurrency, and richer indexing. Teams with a dedicated admin—or a managed service— rarely regret the choice for complex apps.

How often should you vacuum PostgreSQL?

Autovacuum runs continuously by default. You intervene when n_dead_tup stays high on hot tables. Schedule manual VACUUM (ANALYZE) after large bulk imports or data purges. Never disable autovacuum globally.

What is the best backup strategy for PostgreSQL in 2026?

Combine nightly pg_dump custom-format files stored off-server with weekly pg_basebackup plus continuous WAL archiving for PITR. Match retention to compliance needs. Test a full restore every month.

Do Laravel apps need a connection pooler for PostgreSQL?

Once you run more than a few PHP-FPM workers, yes. Each worker can hold idle connections. PgBouncer in transaction pooling mode keeps PostgreSQL max_connections sane without rewriting Eloquent.

Ship PostgreSQL with confidence

PostgreSQL Administration Essentials is not glamorous work. It is what separates a demo database from one that survives bad deploys, holiday traffic, and disk surprises. Install cleanly, back up provably, tune with data, and monitor before users notice. If your team needs hands-on help with PostgreSQL on Ubuntu—or a full Laravel stack built around it—contact us to discuss your project. You can also browse the home page for related guides, or read more about my background on about me and API development work with PostgreSQL backends.

Frequently Asked Questions

PostgreSQL Administration Essentials is installing PostgreSQL securely, automating backups, tuning memory and autovacuum, monitoring bloat, and rehearsing recovery before you need it in production.

Administration sits between your Laravel or Symfony application and the Linux host. A production admin stack has six layers: installation and access control, backup and recovery, performance tuning, monitoring, maintenance, and security. Skip any layer and you will feel it during traffic spikes or a failed deploy. On booking platforms, the database holds itineraries, payments, and supplier records, so admin work is part of shipping reliable software—not an optional afterthought behind PHP code.

Add the official PGDG apt repository on Ubuntu 24.04, then install postgresql-18 and postgresql-client-18. Confirm the cluster with systemctl status postgresql and SELECT version(). Pin the major version you want—PostgreSQL 18 is current, while 17 remains common on managed hosts. Do not mix versions across app servers and replicas. Cross-check package names at postgresql.org/download/linux/ubuntu before pasting commands into CI, because names change between releases.

Never point Laravel at the postgres superuser. Create a database owner role, a separate application user, and optionally a migration role for schema-only deploys. Grant CONNECT on the database, USAGE on the schema, and SELECT, INSERT, UPDATE, DELETE on tables explicitly. Least-privilege app users limit damage if credentials leak through a misconfigured .env file or a compromised worker. This pattern matches what I use on production Laravel applications where the database holds sensitive booking and payment data.

Combine nightly pg_dump custom-format files stored off-server with weekly pg_basebackup plus continuous WAL archiving for point-in-time recovery. Match retention to compliance needs and test a full restore every month.

Autovacuum runs continuously by default. Intervene when n_dead_tup stays high on hot tables, or schedule manual VACUUM (ANALYZE) after bulk imports. Never disable autovacuum globally.

PostgreSQL asks for more upfront tuning and vacuum awareness than MySQL. MySQL often feels simpler on cPanel-style shared hosting, while PostgreSQL rewards teams that plan maintenance windows with stricter SQL, better concurrency, and richer indexing including partial and GIN indexes. Both engines fail the same way when nobody owns backups. Teams with a dedicated admin or managed service rarely regret PostgreSQL for complex Laravel apps, JSON workloads, and predictable concurrency under write-heavy traffic.

Once you run more than a few PHP-FPM workers, yes. Each worker can hold idle connections, and Laravel opens many under load. PgBouncer in transaction pooling mode keeps max_connections sane without rewriting Eloquent queries. Pair a pooler with production starting points of 100–200 max_connections rather than leaving the default at 100 while workers multiply. This is one of the first fixes when pg_stat_activity shows too many idle clients and new requests fail with connection errors.

Schedule nightly pg_dump -Fc dumps for small and mid-size Laravel apps under roughly 50 GB, store files off-server, and prune old dumps after about fourteen days. Test restores monthly on staging with pg_restore—a backup you have never restored is a guess. For point-in-time recovery, enable archive_mode, set wal_level to replica, archive WAL files with archive_command, and take base backups using pg_basebackup. Rehearse the full PITR playbook before your first incident, not during one at 2 AM.

Fix Laravel N+1 queries and missing indexes before chasing exotic server parameters. On an 8 GB RAM VPS running only PostgreSQL, start with shared_buffers around 2 GB, effective_cache_size around 6 GB, work_mem 16 MB, and maintenance_work_mem 512 MB. Set random_page_cost to 1.1 on SSD or NVMe. Tune autovacuum aggressively on heavy write tables like carts and audit logs. Use partial indexes for soft-deleted models and GIN indexes on JSON columns. Offload cache and sessions to Redis 8.10 so PostgreSQL is not doing work Redis handles better.

Set listen_addresses to a private interface IP, not asterisk on a public VPS. Restrict clients in pg_hba.conf with host and hostssl rules using scram-sha-256 for your app subnet only. Enable SSL in production, reload PostgreSQL after changes, and allow port 5432 through UFW only from app subnets. Use TLS so credentials and row data are encrypted in transit. Combine database-level rules with broader Linux hardening—firewall, fail2ban, and limited network exposure—because PostgreSQL security is only as strong as the host around it.

Bookmark essential pg_stat queries: group pg_stat_activity by state for connection counts, filter active queries running longer than thirty seconds, and rank tables by total relation size. Check pg_stat_user_tables for dead tuple percentages on bloat-prone tables. Export metrics to Grafana via postgres_exporter, or run threshold checks from cron that email on breach. Set log_min_duration_statement to 500–1000 ms in production to surface slow queries without log floods. Monitoring turns admin from reactive firefighting into scheduled work with alert thresholds you define upfront.

Disk full on the WAL volume: expand disk, run SELECT pg_switch_wal(), and verify archiving resumes. Too many connections: add PgBouncer in transaction pooling mode and review Laravel DB_PERSISTENT misuse. Lock waits during deploys: set lock_timeout in migration sessions and schedule DDL off-peak. Sequence exhaustion on bigserial tables: monitor pg_sequences on high-insert tables. Permission denied after restore: re-run grants because pg_dump -Fc with --no-owner needs explicit role mapping. Split connection errors from slow-query problems before changing config at random.

pg_dump logical backups are simple and work well for nightly schedules on apps under roughly 50 GB, but they cannot rewind to a specific minute before a bad migration. WAL archiving plus base backups give point-in-time recovery—essential when you need to restore to 14:07 yesterday, not just last night's dump. Enable archive_mode, wal_level replica, and a working archive_command, then prove the full restore path on staging monthly. PostgreSQL Administration Essentials requires both pg_dump schedules and WAL archiving if PITR is a real requirement.

Rehearse the major version upgrade on a clone first—never treat it as a routine package update. PostgreSQL 17 to 18 jumps need extension compatibility checks because extensions that worked on the old cluster may block the upgrade. Verify application connection strings, pg_hba.conf rules, and backup restore paths against the new version. Pin the same major version across app servers and replicas so Laravel workers never hit mixed-version clusters. After upgrade, revalidate autovacuum settings, index health, and monitoring queries against pg_stat views on the new release.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: