initdb & Data Directory
initdb creates a new PostgreSQL cluster on disk. The data directory (PGDATA) holds all databases, WAL, and configuration for that single instance.
Search across all documentation pages
initdb creates a new PostgreSQL cluster on disk. The data directory (PGDATA) holds all databases, WAL, and configuration for that single instance.
sudo -u postgres mkdir -p /var/lib/postgresql/18/main
sudo -u postgres /usr/lib/postgresql/18/bin/initdb \
-D /var/lib/postgresql/18/main \
--encoding=UTF8 \
--locale=C.UTF-8 \
--data-checksumsWhen to reach for this: First cluster on a host, restoring to a blank data directory, or building a standby before pg_basebackup.
# Create dedicated mount points (production pattern)
sudo mkdir -p /data/pgdata /data/pgwal
sudo chown postgres:postgres /data/pgdata /data/pgwal
sudo chmod 700 /data/pgdata /data/pgwal
sudo -u postgres initdb \
-D /data/pgdata \
--waldir=/data/pgwal \
--encoding=UTF8 \
--locale=en_US.UTF-8 \
--data-checksums
# Confirm layout
sudo -u postgres ls -la /data/pgdata
sudo -u postgres ls -la /data/pgdata/baseWhat this demonstrates:
PGDATA and WAL on different volumes for IO isolation700 permissions on data dirs (owner-only access)--data-checksums enables page checksum verification at read timebase/ subdirectory appears after init - one subdir per database OID| Path | Purpose |
|---|---|
postgresql.conf | Main server configuration |
pg_hba.conf | Client authentication rules |
pg_ident.conf | User name maps |
base/ | Per-database data files |
global/ | Cluster-wide catalogs |
pg_wal/ | Write-ahead log (unless --waldir) |
pg_xact/ | Transaction commit status |
PG_VERSION | Major version marker |
# Correct ownership
ls -ld /data/pgdata
# drwx------ postgres postgres
# Wrong: group or world readable
chmod 750 /data/pgdata # avoid - leaks catalog metadata riskpostgres OS user should read/write PGDATA.postgres or use filesystem snapshots with correct UID.initdb as root - the server refuses to start on root-owned data.-- Set at init time; changing later requires re-init
SHOW server_encoding; -- UTF8
SHOW lc_collate; -- en_US.UTF-8
SHOW lc_ctype;UTF8 encoding for all new clusters.C or C.UTF-8 collation gives predictable sort order; locale-specific collation affects index order.--locale-provider=icu) are available in PostgreSQL 15+.# postgresql.conf (if not set at initdb)
# wal_directory is set at init via --waldir; relocate carefully with pg_resetwal only in disaster recoveryinitdb fails if the directory is non-empty. Fix: Use a fresh empty directory or pg_basebackup for replicas.chown from backup tar as root leaves root-owned files. Fix: chown -R postgres:postgres $PGDATA before start.--data-checksums cannot enable them later without re-init. Fix: Enable at init; plan checksum-aware monitoring.lc_collate breaks index ordering assumptions. Fix: Match initdb flags on all nodes in a topology.initdb needs scratch space; running cluster needs headroom for WAL and temp files. Fix: Monitor filesystem % used; keep WAL on separate volume.| Alternative | Use When | Don't Use When |
|---|---|---|
Package-managed init (Debian pg_createcluster) | Standard apt installs | You need custom paths on day one |
pg_basebackup | Standby or PITR seed | Brand-new empty primary with no source |
| Managed cloud "Create instance" | No host access | You need filesystem-level control |
PGDATA is one cluster (instance). A cluster contains many databases (postgres, myapp, etc.). One postgres process manages one PGDATA.
Yes, with care: stop the server, move the directory, update systemd Environment=PGDATA=, or use pg_ctl -D. Do not move live files while the server runs.
Catalog files contain schema metadata and connection info. World-readable data directories are a finding in security audits.
Yes for new production clusters. Small CPU cost buys early detection of silent storage corruption.
WAL segments live under the path you pass to --waldir, symlinked from $PGDATA/pg_wal. Both paths must be available at start.
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.
Reviewed by Chris St. John·Last updated Jul 18, 2026