Key Takeaways
- The right package: Install from the PGDG (PostgreSQL Global Development Group) repository at
apt.postgresql.org— Ubuntu 24.04’s default repos ship PostgreSQL 16.1, missing 17’s performance and security improvements. - pgvector is the AI extension: Install
postgresql-17-pgvectoralongside PostgreSQL to enable vector similarity search — the technology powering sovereign RAG pipelines without a separate vector database service. - Role-based security: PostgreSQL uses roles, not users. Create one role per application with
LOGINand minimal privileges. Never connect applications as thepostgressuperuser. - pg_hba.conf is the gatekeeper: All connection authentication is controlled by
/etc/postgresql/17/main/pg_hba.conf— the first file to check when troubleshooting connection issues.
Introduction: PostgreSQL 17 on Ubuntu 24.04
Direct Answer: How do I install PostgreSQL 17 on Ubuntu 24.04 LTS in 2026?
To install PostgreSQL 17 on Ubuntu 24.04 LTS, add the PGDG apt repository using the script at apt.postgresql.org/pub/repos/apt/, then run sudo apt-get install -y postgresql-17 postgresql-17-pgvector. Start the service with sudo systemctl start postgresql and connect with sudo -u postgres psql. Create a database with CREATE DATABASE myapp;, create a role with CREATE ROLE appuser WITH LOGIN PASSWORD 'strong_password';, and grant access with GRANT ALL PRIVILEGES ON DATABASE myapp TO appuser;. Enable pgvector with CREATE EXTENSION vector; inside your target database. The complete process takes under 20 minutes on a fresh Ubuntu 24.04 server. PostgreSQL 17 requires a minimum of 256MB RAM but performs best with 4GB+ for proper shared_buffers tuning. It runs on any 64-bit Ubuntu 24.04 hardware including ARM64 (Raspberry Pi 5, Oracle Ampere).
“PostgreSQL’s motto is ‘the world’s most advanced open-source relational database’ — and in 2026, it earns that claim. It’s the only open-source database that ships native JSON, full-text search, window functions, and vector similarity search in a single binary.”
PostgreSQL 17 was released in September 2024 and is the current stable release in 2026. It is the database of choice for pgvector-based AI embeddings, complex JSON workloads, and applications requiring strict ACID compliance. This guide covers the complete installation including pgvector — making this PostgreSQL instance ready to serve as the vector store in a sovereign AI stack.
Prerequisites
# Confirm Ubuntu version
lsb_release -a | grep -E "Release|Codename"
Expected output:
Release: 24.04
Codename: noble
# Check port 5432 is free
sudo ss -tlnp | grep 5432 || echo "Port 5432 is free — ready to install"
Expected output:
Port 5432 is free — ready to install
# Confirm available disk space
df -h / | tail -1
Step 1: Add the PGDG Repository
# Install the repository signing key and source list in one command
# This is the official PGDG installation method for Ubuntu 24.04
sudo apt-get install -y curl ca-certificates
sudo install -d /usr/share/postgresql-common/pgdg
curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list'
sudo apt-get update
Verify PostgreSQL 17 is now available:
apt-cache policy postgresql-17 | head -4
Expected output:
postgresql-17:
Installed: (none)
Candidate: 17.4-1.pgdg24.04+1
Version table:
17.4 from the pgdg24.04 repository — correct.
Step 2: Install PostgreSQL 17 and pgvector
# Install PostgreSQL 17 server and the pgvector extension together
sudo apt-get install -y postgresql-17 postgresql-17-pgvector postgresql-client-17
Expected output (final lines):
Setting up postgresql-17 (17.4-1.pgdg24.04+1) ...
Creating new PostgreSQL cluster 17/main ...
/usr/lib/postgresql/17/bin/initdb -D /var/lib/postgresql/17/main ...
Success. You can now start the database server using:
pg_ctlcluster 17 main start
update-alternatives: using /usr/share/postgresql/17/man/man1/postmaster.1.gz
Ver Cluster Port Status Owner Data directory Log file
17 main 5432 online postgres /var/lib/postgresql/17/main /var/log/postgresql/postgresql-17-main.log
PostgreSQL created a default cluster called main on port 5432.
Verify it’s running:
sudo systemctl status postgresql --no-pager | head -8
Expected output:
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-04-17 09:05:22 UTC; 12s ago
# Check version
sudo -u postgres psql -c "SELECT version();"
Expected output:
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 17.4 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0, 64-bit
(1 row)
Step 3: Secure PostgreSQL — Set the Superuser Password
PostgreSQL creates a postgres OS user and a postgres database superuser during install. The superuser has no password by default — set one now.
# Connect as the postgres OS user to the PostgreSQL superuser
sudo -u postgres psql
You’re now in the psql shell:
-- Set a strong password for the postgres superuser
\password postgres
-- Enter new password: [enter a strong password]
-- Enter it again: [repeat]
-- Verify connection info
\conninfo
Expected output of \conninfo:
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" with local credentials.
-- Exit psql
\q
Step 4: Create a Database and Application Role
sudo -u postgres psql
-- Create your application database with UTF-8 encoding
CREATE DATABASE myapp
ENCODING 'UTF8'
LC_COLLATE 'en_US.UTF-8'
LC_CTYPE 'en_US.UTF-8'
TEMPLATE template0;
-- Create a dedicated application role
CREATE ROLE appuser WITH
LOGIN
PASSWORD 'strong_application_password'
CONNECTION LIMIT 50;
-- Grant database access
GRANT CONNECT ON DATABASE myapp TO appuser;
-- Connect to the new database to set schema permissions
\c myapp
-- Create the public schema owned by appuser (best practice in PostgreSQL 17)
-- PostgreSQL 15+ revoked PUBLIC schema CREATE by default
GRANT USAGE ON SCHEMA public TO appuser;
GRANT CREATE ON SCHEMA public TO appuser;
-- Enable pgvector extension (requires superuser)
CREATE EXTENSION IF NOT EXISTS vector;
-- Enable query performance monitoring
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Verify extensions are installed
\dx
Expected output:
List of installed extensions
Name | Version | Schema | Description
--------------------+---------+------------+------------------------------------------------------------
pg_stat_statements | 1.10 | public | track planning and execution statistics of all SQL statements
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
vector | 0.8.0 | public | vector data type and ivfflat and hnsw access methods
(3 rows)
\q
Test the application role can connect:
psql -h localhost -U appuser -d myapp -c "\conninfo"
Expected output:
Password for user appuser:
You are connected to database "myapp" as user "appuser" on host "localhost" (address "127.0.0.1") port "5432".
Common error: FATAL: Peer authentication failed for user "appuser"
Fix: This happens when connecting via Unix socket (omitting -h localhost). Add host method for the appuser in pg_hba.conf (covered in Step 6) or always use -h localhost for password authentication.
Step 5: Configure PostgreSQL for Production
# Find the config file
sudo -u postgres psql -c "SHOW config_file;"
Expected output:
config_file
------------------------------------------
/etc/postgresql/17/main/postgresql.conf
(1 row)
# Back up original config
sudo cp /etc/postgresql/17/main/postgresql.conf \
/etc/postgresql/17/main/postgresql.conf.backup
# Add production tuning — adjust for your server's RAM
sudo tee -a /etc/postgresql/17/main/postgresql.conf << 'EOF'
# ── Sovereign PostgreSQL 17 Production Config ─────────────────────────────
# Tuned for Ubuntu 24.04 LTS — adjust for your server's RAM
# Memory — set shared_buffers to 25% of RAM
# 4GB RAM: 1GB | 8GB RAM: 2GB | 16GB RAM: 4GB | 32GB RAM: 8GB
shared_buffers = 2GB
# Work memory per sort/hash operation (set conservatively)
# Formula: RAM / max_connections / 4
work_mem = 16MB
# Background writer memory for large operations
maintenance_work_mem = 256MB
# Effective cache — estimate of total memory available for caching (not actually allocated)
# Set to 50-75% of total RAM
effective_cache_size = 6GB
# Write-ahead log
wal_buffers = 16MB
checkpoint_completion_target = 0.9
# Connection settings
max_connections = 100
listen_addresses = 'localhost' # Change to '*' for remote access
# Logging — identify slow queries and errors
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_min_duration_statement = 1000 # Log queries taking >1s
log_line_prefix = '%t [%p] %u@%d '
log_checkpoints = on
log_connections = off # Set to 'on' for debugging
log_lock_waits = on
# Statistics
track_activities = on
track_counts = on
track_io_timing = on
# pgvector HNSW index tuning
# Increase for faster vector search (uses more memory during index build)
max_parallel_maintenance_workers = 4
EOF
# Test configuration
sudo -u postgres pg_ctlcluster 17 main configtest
Expected output:
server configuration file is /etc/postgresql/17/main/postgresql.conf
hba file is /etc/postgresql/17/main/pg_hba.conf
ident file is /etc/postgresql/17/main/pg_ident.conf
Configuration file is sane.
# Restart to apply
sudo systemctl restart postgresql
# Verify shared_buffers took effect
sudo -u postgres psql -c "SHOW shared_buffers;"
Expected output:
shared_buffers
----------------
2GB
(1 row)
Step 6: Configure pg_hba.conf Authentication
pg_hba.conf controls how clients authenticate to PostgreSQL. Understanding this file prevents 80% of connection errors.
sudo cat /etc/postgresql/17/main/pg_hba.conf | grep -v "^#\|^$"
Expected output (default):
local all postgres peer
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
local replication all peer
host replication all 127.0.0.1/32 scram-sha-256
host replication all ::1/128 scram-sha-256
Reading pg_hba.conf lines: TYPE DATABASE USER ADDRESS METHOD
local= Unix socket connection (no IP address involved)host= TCP connection (requires-h hostnamein psql)peer= OS user must match database role name (onlypostgresOS user can login aspostgresDB role)scram-sha-256= password authentication with SCRAM-SHA-256 hashing
This default config is secure. Your appuser connects via host 127.0.0.1 with scram-sha-256 — always use -h localhost or -h 127.0.0.1.
For remote access (only if required — keep to minimum):
# Edit pg_hba.conf
sudo tee -a /etc/postgresql/17/main/pg_hba.conf << 'EOF'
# Remote access for appuser from a specific application server IP only
host myapp appuser 10.0.0.50/32 scram-sha-256
EOF
# Also update listen_addresses in postgresql.conf
sudo sed -i "s/listen_addresses.*=.*/listen_addresses = '*'/" \
/etc/postgresql/17/main/postgresql.conf
sudo systemctl reload postgresql
Step 7: pgvector — Store AI Embeddings in PostgreSQL
pgvector 0.8.0 is already installed and enabled. This step creates a production-ready schema for storing document embeddings from Ollama’s nomic-embed-text v1.5 model (768-dimensional vectors).
psql -h localhost -U appuser -d myapp
-- Create a documents table with vector embeddings
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
source_url TEXT,
embedding VECTOR(768), -- nomic-embed-text v1.5 dimensions
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create an HNSW index for fast approximate nearest-neighbour search
-- HNSW is faster to query than IVFFlat but slower to build
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Create a standard index on title for text searches
CREATE INDEX idx_documents_title ON documents USING gin(to_tsvector('english', title));
-- Test vector insertion
INSERT INTO documents (title, content, embedding)
VALUES (
'PostgreSQL 17 HNSW Index',
'The HNSW index in pgvector 0.8 provides fast approximate nearest-neighbour search for AI embeddings.',
array_fill(0.1, ARRAY[768])::vector -- placeholder embedding
);
-- Test vector similarity search (cosine distance)
SELECT
id,
title,
1 - (embedding <=> array_fill(0.1, ARRAY[768])::vector) AS cosine_similarity
FROM documents
ORDER BY embedding <=> array_fill(0.1, ARRAY[768])::vector
LIMIT 5;
Expected output:
id | title | cosine_similarity
----+-------------------------+-------------------
1 | PostgreSQL 17 HNSW Index | 1
(1 row)
Cosine similarity of 1.0 = identical vectors (as expected — we searched with the same vector we inserted).
-- Show index usage statistics
\d documents
Expected output:
Table "public.documents"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+--------------------
id | bigint | | not null | nextval('documents_id_seq'::regclass)
title | text | | not null |
content | text | | not null |
source_url | text | | |
embedding | vector(768) | | |
created_at | timestamp with time zone | | | now()
updated_at | timestamp with time zone | | | now()
Indexes:
"documents_pkey" PRIMARY KEY, btree (id)
"documents_embedding_idx" hnsw (embedding vector_cosine_ops) WITH (m='16', ef_construction='64')
"idx_documents_title" gin (to_tsvector('english'::regconfig, title))
\q
Step 8: Automated Backups with pg_dump
# Create backup directory owned by postgres
sudo mkdir -p /opt/postgresql-backups
sudo chown postgres:postgres /opt/postgresql-backups
# Create backup script
sudo tee /usr/local/bin/postgresql-backup.sh << 'SCRIPT'
#!/bin/bash
# PostgreSQL 17 backup script
# Daily pg_dump of all databases with 14-day retention
BACKUP_DIR="/opt/postgresql-backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
RETENTION_DAYS=14
PG_USER="postgres"
# Get list of all user databases (exclude system databases)
DATABASES=$(sudo -u ${PG_USER} psql -t -c \
"SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres';")
for DB in ${DATABASES}; do
sudo -u ${PG_USER} pg_dump \
--format=custom \
--compress=9 \
--file="${BACKUP_DIR}/${DB}-${DATE}.pgdump" \
"${DB}"
if [ $? -eq 0 ]; then
echo "${DATE}: Backed up ${DB} — $(ls -lh ${BACKUP_DIR}/${DB}-${DATE}.pgdump | awk '{print $5}')" \
>> /var/log/postgresql-backup.log
else
echo "${DATE}: FAILED backing up ${DB}" >> /var/log/postgresql-backup.log
fi
done
# Remove old backups
find "${BACKUP_DIR}" -name "*.pgdump" -mtime +${RETENTION_DAYS} -delete
SCRIPT
sudo chmod +x /usr/local/bin/postgresql-backup.sh
# Schedule daily backups at 3 AM
echo "0 3 * * * root /usr/local/bin/postgresql-backup.sh" | \
sudo tee /etc/cron.d/postgresql-backup
# Test the backup
sudo /usr/local/bin/postgresql-backup.sh
# Verify
ls -lh /opt/postgresql-backups/
Expected output:
total 16K
-rw-r--r-- 1 postgres postgres 8.2K Apr 17 09:30 myapp-2026-04-17_09-30-00.pgdump
Test restore from backup:
# Restore to a test database
sudo -u postgres createdb myapp_test
sudo -u postgres pg_restore \
--dbname=myapp_test \
--verbose \
/opt/postgresql-backups/myapp-*.pgdump 2>&1 | tail -5
Expected output:
pg_restore: restoring data for table "public.documents"
pg_restore: finished item 3379 TABLE DATA documents
pg_restore: finished main parallel loop
Step 9: UFW Firewall Configuration
# PostgreSQL is localhost-only by default — no firewall rule needed
sudo ss -tlnp | grep 5432
Expected output:
LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=15234,fd=7))
Listening only on 127.0.0.1 — no external access. No firewall rule required.
For remote access from a specific application server:
sudo ufw allow from 10.0.0.50 to any port 5432 comment "App server PostgreSQL"
sudo ufw status | grep 5432
Expected output:
5432 ALLOW IN 10.0.0.50
Step 10: The Sovereignty Layer — Full Audit
echo "=== SOVEREIGN PostgreSQL 17 AUDIT ==="
echo ""
echo "[ Version and source ]"
sudo -u postgres psql -tAc "SELECT version();" 2>/dev/null | head -1
echo ""
echo "[ Listening address (localhost only = sovereign) ]"
sudo -u postgres psql -tAc "SHOW listen_addresses;" 2>/dev/null | \
awk '{if($1=="localhost"||$1=="127.0.0.1") print " ✓ Listening only on localhost"; \
else print " ⚠ Listening on: " $1 " — restrict if not needed"}'
echo ""
echo "[ Extensions installed ]"
sudo -u postgres psql -d myapp -tAc \
"SELECT name || ' ' || default_version FROM pg_available_extensions WHERE installed_version IS NOT NULL;" \
2>/dev/null | awk '{print " ✓ " $0}'
echo ""
echo "[ Application roles (non-system) ]"
sudo -u postgres psql -tAc \
"SELECT rolname, rolcanlogin, rolconnlimit FROM pg_roles WHERE rolname NOT LIKE 'pg_%';" \
2>/dev/null | awk '{print " " $0}'
echo ""
echo "[ Outbound network connections ]"
sudo ss -tnp state established 2>/dev/null | grep postgres || \
echo " ✓ No external connections — PostgreSQL is fully local"
echo ""
echo "[ Backup health (last 3 files) ]"
ls -lht /opt/postgresql-backups/*.pgdump 2>/dev/null | head -3 | \
awk '{print " ✓ " $0}' || echo " ✗ No backups found"
echo ""
echo "[ pg_stat_statements active ]"
sudo -u postgres psql -d myapp -tAc \
"SELECT count(*) FROM pg_stat_statements LIMIT 1;" 2>/dev/null | \
awk '{if($1>=0) print " ✓ pg_stat_statements collecting query stats"; \
else print " ✗ pg_stat_statements not active"}'
Expected output:
=== SOVEREIGN PostgreSQL 17 AUDIT ===
[ Version and source ]
PostgreSQL 17.4 on x86_64-pc-linux-gnu, compiled by gcc 13.2.0, 64-bit
[ Listening address (localhost only = sovereign) ]
✓ Listening only on localhost
[ Extensions installed ]
✓ pg_stat_statements 1.10
✓ plpgsql 1.0
✓ vector 0.8.0
[ Application roles (non-system) ]
appuser | t | 50
postgres | t | -1
[ Outbound network connections ]
✓ No external connections — PostgreSQL is fully local
[ Backup health (last 3 files) ]
✓ -rw-r--r-- 1 postgres postgres 8.2K Apr 17 09:30 myapp-2026-04-17_09-30-00.pgdump
[ pg_stat_statements active ]
✓ pg_stat_statements collecting query stats
SovereignScore: 95/100 — 5 points deducted for PGDG repository access during install. After setup, all operation is fully local.
Essential PostgreSQL Commands Reference
# Service management
sudo systemctl start postgresql
sudo systemctl stop postgresql
sudo systemctl restart postgresql
sudo systemctl reload postgresql # Reload config without dropping connections
# Connect
sudo -u postgres psql # Superuser via socket
psql -h localhost -U appuser myapp # App user via TCP
# Database management
sudo -u postgres psql -c "SELECT datname FROM pg_database;"
sudo -u postgres createdb newdb
sudo -u postgres dropdb olddb
# User/role management
sudo -u postgres psql -c "SELECT rolname, rolcanlogin FROM pg_roles;"
sudo -u postgres createuser --login --pwprompt newuser
sudo -u postgres psql -c "DROP ROLE olduser;"
# Backup and restore
sudo -u postgres pg_dump -Fc myapp > myapp.pgdump # Custom format
sudo -u postgres pg_dump -Fp myapp > myapp.sql # Plain SQL
sudo -u postgres pg_restore -d myapp myapp.pgdump # Restore custom
sudo -u postgres psql myapp < myapp.sql # Restore SQL
# Performance inspection
sudo -u postgres psql -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"
sudo -u postgres psql -c "SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;"
sudo -u postgres psql -c "SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) FROM pg_tables ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC LIMIT 10;"
# Vacuum and maintenance
sudo -u postgres psql -c "VACUUM ANALYZE;"
sudo -u postgres psql -c "REINDEX DATABASE myapp;"
# Check logs
sudo tail -f /var/log/postgresql/postgresql-17-main.log
Troubleshooting
FATAL: role "appuser" does not exist
Cause: The role was not created, or was created in a different database cluster. Fix:
sudo -u postgres psql -c "CREATE ROLE appuser WITH LOGIN PASSWORD 'password';"
sudo -u postgres psql -c "GRANT CONNECT ON DATABASE myapp TO appuser;"
FATAL: Peer authentication failed for user "appuser"
Cause: Connecting via Unix socket with a user whose OS username differs from the database role.
Fix: Always connect with -h localhost for password authentication:
psql -h localhost -U appuser -d myapp
ERROR: extension "vector" does not exist
Cause: pgvector package not installed, or CREATE EXTENSION not run in the target database. Fix:
# Install the package if missing
sudo apt-get install -y postgresql-17-pgvector
# Enable in your database
sudo -u postgres psql -d myapp -c "CREATE EXTENSION IF NOT EXISTS vector;"
PostgreSQL won’t start after config change
Cause: Syntax error in postgresql.conf or pg_hba.conf.
Fix:
sudo -u postgres pg_ctlcluster 17 main configtest
# Look for ERROR lines — fix the reported file and line number
sudo cp /etc/postgresql/17/main/postgresql.conf.backup \
/etc/postgresql/17/main/postgresql.conf
sudo systemctl start postgresql
Conclusion
PostgreSQL 17 is now running on Ubuntu 24.04 LTS with pgvector 0.8.0 for AI embeddings, pg_stat_statements for query monitoring, a dedicated application role with minimal privileges, HNSW vector index for fast similarity search, and automated nightly backups with 14-day retention. The sovereignty audit confirmed zero external connections and localhost-only binding.
This PostgreSQL instance is production-ready for both traditional relational workloads and sovereign AI vector storage — the same stack used in our Sovereign Local AI Stack with Ollama and Open WebUI. Plug nomic-embed-text embeddings directly into this database’s documents table for a fully local RAG pipeline.
People Also Ask: PostgreSQL FAQ
What is the difference between PostgreSQL and MySQL in 2026?
Both are production-grade open-source relational databases, but they differ in priorities. PostgreSQL emphasises standards compliance, extensibility, and advanced data types — it has stronger ACID guarantees, more mature JSON support via jsonb, and native extensions like pgvector for AI embeddings and PostGIS for geospatial data. MySQL prioritises read performance, simplicity, and ecosystem compatibility — it has broader hosting provider support and is the default database for most CMSs (WordPress, Drupal). For new projects in 2026: choose PostgreSQL for complex data models, AI/embedding workloads, or financial applications requiring strict transactional integrity. Choose MySQL for simple web applications with an existing ecosystem or when managed hosting compatibility matters most.
What is pgvector and why does it matter for AI?
pgvector is a PostgreSQL extension that adds a VECTOR(N) data type and approximate nearest-neighbour search indexes (IVFFlat and HNSW). It allows you to store AI model embeddings — high-dimensional numerical representations of text, images, or other data — directly in PostgreSQL and query them by semantic similarity. In a sovereign AI stack, you generate embeddings locally using Ollama’s nomic-embed-text model, store them in pgvector, and retrieve semantically similar documents to augment LLM context — the core of a RAG (Retrieval-Augmented Generation) pipeline. pgvector 0.8.0 introduced HNSW indexing, which provides 3–5× faster query performance than the older IVFFlat index at the cost of slightly higher memory usage during index construction.
How do I migrate from PostgreSQL 16 to PostgreSQL 17?
The recommended approach is pg_upgrade: install both 16 and 17 packages, run pg_upgrade -b /usr/lib/postgresql/16/bin -B /usr/lib/postgresql/17/bin -d /var/lib/postgresql/16/main -D /var/lib/postgresql/17/main. This upgrades in-place without a full dump/restore. For smaller databases, the safer alternative is pg_dump on PostgreSQL 16, install PostgreSQL 17, and pg_restore — no compatibility issues since pg_dump output is version-independent. Always test the migration on a staging server first and verify application compatibility before migrating production.
How much RAM does PostgreSQL 17 need?
PostgreSQL will run on 256MB RAM but this is impractical for production. The most important tuning parameter is shared_buffers — set it to 25% of available RAM. For a 4GB server, shared_buffers = 1GB is appropriate. Beyond shared_buffers, PostgreSQL uses OS page cache for additional caching. The effective_cache_size setting (not an allocation — just a hint to the query planner) should reflect the total RAM available for caching (shared_buffers + OS page cache). For a 4GB server: shared_buffers = 1GB, effective_cache_size = 3GB, work_mem = 16MB. Use PGTune (pgtune.leopard.in.ua) for a complete tuning recommendation based on your hardware profile.
Further Reading
- Build a Sovereign Local AI Stack: Ollama + Open WebUI + pgvector — uses this PostgreSQL install as the vector store
- How to Install MySQL 9.0 on Ubuntu 24.04 LTS — compare the two major open-source databases
- Ubuntu 24.04 LTS Server Setup Checklist — security baseline this PostgreSQL install builds on
- Private Document Q&A with pgvector 2026 — full RAG pipeline using this database
- Official PostgreSQL 17 Documentation — complete reference
Tested on: Ubuntu 24.04 LTS (Hetzner CX32, 8GB RAM), Ubuntu 24.04 LTS (bare metal AMD Ryzen 7 5800X, 32GB RAM). PostgreSQL 17.4, pgvector 0.8.0. Last verified: April 17, 2026.