What's changed: Initial version (topic G1)
1.1Building the Database Server
Go deep on the encryption, authentication, and audit foundations laid down when building a server: SSL communication and data encryption with pgcrypto, checking encryption status with pg_stat_ssl, client authentication via SCRAM-SHA-256, the audit-log core log_statement plus the activity-statistics settings track_functions, track_activities, pinning parameters per user/database with ALTER ROLE/ALTER DATABASE, checksum-enabled initialization with initdb --data-checksums, and key cluster directories pg_tblspc, pg_wal, pg_stat_tmp.
Where Silver was about getting a server running, Gold raises the bar to a server that can withstand an audit, encrypts traffic, and detects tampering. A production server is only truly "built" once you have encrypted communication, a secure password verification method, an audit trail of who did what, and checksums that catch disk corruption early. This section walks through these four pillars in the order you would actually harden a server.
1.1.1SSL communication and data encryption
- SSL encrypts the communication channel between client and server. Enable it with
ssl = oninpostgresql.confand provide a server certificate and private key (ssl_cert_file/ssl_key_file). Ahostsslline inpg_hba.confcan enforce SSL-only connections. - pgcrypto is an extension (
CREATE EXTENSION pgcrypto) for encrypting the stored data itself, not the wire. It provides functions likecrypt()(password hashing) andpgp_sym_encrypt()/pgp_sym_decrypt()(symmetric encryption)—covering data-at-rest encryption, which SSL does not. - pg_stat_ssl is a system view showing each backend's SSL connection status (whether SSL is used, protocol version, cipher suite). Joining it with
pg_stat_activityonpidlets you audit which sessions are actually SSL-encrypted.
1.1.2Client authentication and audit logging
- SCRAM-SHA-256 is the most secure password-based auth method selectable in
pg_hba.conf. Unlikemd5, whose hash sits in the catalog and is weaker against replay-style attacks, SCRAM-SHA-256 uses a challenge-response exchange that never sends the password itself. New builds should adopt it as the default (password_encryption = scram-sha-256). - The core of audit logging is log_statement (
none/ddl/mod/all—how much of the executed SQL text itself gets logged). track_functions (whether PL/pgSQL function-call stats are aggregated intopg_stat_user_functions) and track_activities (whether currently running queries are reflected inpg_stat_activity) are activity-statistics/monitoring settings, not audit logging, and should be distinguished from log_statement. - ALTER ROLE/ALTER DATABASE pin
SETparameters per user or per database—e.g.,ALTER ROLE app_user SET statement_timeout = '30s'forces that behavior only for a specific role. For an audit requirement like "this user must always log full statements," useALTER ROLE audit_user SET log_statement = 'all'.
Most-tested distinctions: wire encryption = SSL, data-at-rest encryption = pgcrypto; the strongest password auth = SCRAM-SHA-256 (superior to md5); pinning parameters per user/DB = ALTER ROLE/ALTER DATABASE. Also a staple: log_statement (audit log) versus track_functions/track_activities (activity statistics) each record a different thing—the SQL text itself, function-call stats, or currently running queries—so do not conflate track_* with audit logging.
Walk through the practical new-server build flow. First, initialize the cluster with initdb --data-checksums. This is an option that can only be chosen at build time—it cannot be turned on after initdb has run—and from then on every page carries a checksum, letting you detect physical disk corruption (bit rot) on read. Next, set ssl = on in postgresql.conf, install a server certificate, and standardize every pg_hba.conf line on scram-sha-256 authentication (replacing any lingering md5 lines). If there is an audit requirement, scope it appropriately with log_statement = 'mod' (log only modifying statements) or track_functions = pl (aggregate only PL-language functions), and force full-statement logging for a specific sensitive role with ALTER ROLE finance_admin SET log_statement = 'all'. For especially sensitive stored columns (e.g., national ID or credit card numbers), encrypt them with pgcrypto's pgp_sym_encrypt(column, key) and decrypt on read with pgp_sym_decrypt(). After building, confirm SSL is actually in effect with a query like SELECT pid, ssl, version, cipher FROM pg_stat_ssl JOIN pg_stat_activity USING (pid);. You also need to know the cluster's directory layout: pg_tblspc holds symlinks to tablespaces, pg_wal (formerly pg_xlog) holds WAL segment files, and pg_stat_tmp holds temporary statistics files, whose location can be changed with stats_temp_directory (some operators point it at tmpfs to cut disk I/O).
| Item | Role | Key point |
|---|---|---|
| SSL | Wire encryption | ssl=on; hostssl lines can enforce it |
| pgcrypto | Data-at-rest encryption | pgp_sym_encrypt/decrypt, crypt() |
| SCRAM-SHA-256 | Password auth | Challenge-response, safer than md5 |
| initdb --data-checksums | Page checksums | Build-time only; cannot enable later |
Trap: "Using pgcrypto makes SSL unnecessary" is wrong—pgcrypto encrypts data at rest while SSL encrypts the wire; they serve different purposes and complement each other. Also wrong: "checksums can be enabled after initdb via ALTER SYSTEM"—data_checksums is decided only at initdb time; enabling it on an existing cluster requires something closer to rebuilding the cluster (e.g., an offline pg_checksums --enable), and this note prioritizes the initdb-time understanding.
1.1.3Section summary
- SSL = wire encryption / pgcrypto = data-at-rest encryption; check status with pg_stat_ssl. SCRAM-SHA-256 is the most secure auth method
- Audit log = log_statement (SQL text) / activity stats = track_functions (function stats), track_activities (running queries) (track_* are not audit logging); pin per user/DB with ALTER ROLE/DATABASE
- initdb --data-checksums is build-time only. Cluster directories: pg_tblspc (tablespace links), pg_wal (WAL), pg_stat_tmp (stats temp files)
Sign in to track progress — Log in.
Quick check
(just a quick review)Q1. You are initializing a new database cluster and want to detect future disk corruption early. Which option should you specify when running initdb?
Q2. You want to ensure that all executed SQL statements are always logged, but only for a specific administrator role. What is the appropriate way to configure this?
Q3. You want to encrypt and store a specific column of data at rest inside a table. Which extension is best suited for this purpose?

