La sauvegarde et la restauration PostgreSQL constituent le socle de tout plan de reprise après sinistre. Que vous protégiez une seule base applicative ou gériez des centaines d’instances, maîtriser pg_dump et pg_restore vous garantit de pouvoir récupérer après une panne matérielle, une suppression accidentelle ou une migration ratée. Ce guide couvre tous les aspects pratiques — des dumps basiques jusqu’à la planification automatisée, la restauration sélective, et l’étape critique que la plupart des équipes négligent : tester réellement que les sauvegardes peuvent être restaurées.

Prérequis

  • PostgreSQL 12 ou version ultérieure installé et en cours d’exécution
  • Accès à une base de données PostgreSQL avec des privilèges suffisants (pg_dump requiert au minimum un accès en lecture sur tous les objets)
  • Accès sudo ou à l’utilisateur postgres sur le serveur de base de données
  • Connaissance de base de SQL et des concepts PostgreSQL (bases de données, schémas, tables)

Créer des sauvegardes avec pg_dump

pg_dump produit des sauvegardes logiques — une représentation de votre base de données sous forme d’instructions SQL ou d’une archive compressée. Contrairement aux copies au niveau du système de fichiers, ces sauvegardes sont portables entre les versions de PostgreSQL et les plateformes.

Dump SQL brut (format par défaut)

La sauvegarde la plus simple crée un fichier .sql contenant toutes les commandes SQL nécessaires pour recréer la base :

# Exporter une seule base de données vers un fichier SQL
pg_dump -U postgres -h localhost mydb > mydb_backup.sql

# Inclure l'instruction CREATE DATABASE
pg_dump -U postgres -h localhost -C mydb > mydb_backup_with_create.sql

# Dump avec horodatage dans le nom de fichier
pg_dump -U postgres mydb > "mydb_$(date +%Y%m%d_%H%M%S).sql"

Le format SQL brut est lisible par un humain et peut être restauré avec psql. L’inconvénient : il ne prend pas en charge la restauration parallèle ni la restauration sélective de tables.

Format personnalisé (-Fc) — Recommandé en production

Le format personnalisé crée une archive compressée et non textuelle qui offre les options de restauration les plus flexibles :

# Sauvegarde au format personnalisé (compressée par défaut)
pg_dump -U postgres -Fc mydb > mydb_backup.dump

# Format personnalisé avec compression maximale
pg_dump -U postgres -Fc -Z 9 mydb > mydb_backup.dump

# Format personnalisé avec dump parallèle (4 workers)
pg_dump -U postgres -Fc -j 4 mydb > mydb_backup.dump

Pourquoi le format personnalisé est préféré :

  • Compression automatique (généralement 5 à 10 fois plus petit qu’un dump SQL brut)
  • Restauration parallèle possible avec pg_restore -j
  • Restauration sélective (tables, schémas ou données spécifiques)
  • Réordonnancement des éléments lors de la restauration pour optimiser la vitesse de chargement

Format répertoire (-Fd) — Idéal pour les grandes bases

Le format répertoire crée un dossier contenant un fichier par table, ce qui permet de véritables dumps parallèles :

# Format répertoire avec dump parallèle (8 workers)
pg_dump -U postgres -Fd -j 8 -f /backup/mydb_dir mydb

Cela crée un répertoire contenant un fichier toc.dat (table des matières) et un fichier compressé par table. Le dump parallèle réduit considérablement le temps de sauvegarde pour les grandes bases.

Sauvegarde de toutes les bases (pg_dumpall)

Pour sauvegarder toutes les bases du cluster PostgreSQL, ainsi que les objets globaux (rôles, tablespaces) :

# Exporter toutes les bases et les objets globaux
pg_dumpall -U postgres > all_databases.sql

# Exporter uniquement les objets globaux (rôles, tablespaces)
pg_dumpall -U postgres --globals-only > globals.sql

pg_dumpall produit toujours du SQL brut. Pour les clusters de grande taille, exportez les objets globaux séparément et utilisez pg_dump par base de données en format personnalisé.

Dumps sélectifs

# Exporter une seule table
pg_dump -U postgres -t users mydb > users_table.sql

# Exporter plusieurs tables spécifiques
pg_dump -U postgres -t users -t orders -t products mydb > selected_tables.sql

# Exporter un schéma spécifique
pg_dump -U postgres -n public mydb > public_schema.sql

# Exporter le schéma uniquement (sans les données)
pg_dump -U postgres -s mydb > schema_only.sql

# Exporter les données uniquement (sans le schéma)
pg_dump -U postgres -a mydb > data_only.sql

# Exclure une grande table du dump
pg_dump -U postgres -T audit_log mydb > mydb_no_audit.sql

Restaurer des sauvegardes

Restauration depuis un dump SQL brut

# Restaurer dans une base existante
psql -U postgres -h localhost mydb < mydb_backup.sql

# Créer la base et restaurer (si le dump inclut l'option -C)
psql -U postgres -h localhost < mydb_backup_with_create.sql

# Restaurer avec sortie verbeuse
psql -U postgres -v ON_ERROR_STOP=1 mydb < mydb_backup.sql

L’option ON_ERROR_STOP=1 force psql à s’arrêter à la première erreur au lieu de continuer silencieusement. Utilisez toujours cette option lors de la restauration de bases de production.

Restauration depuis un format personnalisé

# Restauration basique
pg_restore -U postgres -d mydb mydb_backup.dump

# Restauration parallèle (8 workers — nettement plus rapide pour les grandes bases)
pg_restore -U postgres -d mydb -j 8 mydb_backup.dump

# Restaurer dans une nouvelle base
createdb -U postgres mydb_restored
pg_restore -U postgres -d mydb_restored mydb_backup.dump

# Supprimer les objets existants avant la restauration
pg_restore -U postgres -d mydb --clean --if-exists mydb_backup.dump

Restauration de tables spécifiques

# Restaurer une seule table depuis un dump au format personnalisé
pg_restore -U postgres -d mydb -t users mydb_backup.dump

# Restaurer à partir d'un fichier liste (contrôle fin)
pg_restore -l mydb_backup.dump > restore_list.txt
# Éditez restore_list.txt — commentez les éléments à exclure
pg_restore -U postgres -d mydb -L restore_list.txt mydb_backup.dump

Restauration d’un schéma spécifique

# Restaurer uniquement le schéma 'public'
pg_restore -U postgres -d mydb -n public mydb_backup.dump

# Restaurer les données uniquement (le schéma existe déjà)
pg_restore -U postgres -d mydb -a mydb_backup.dump

Comparaison des méthodes de sauvegarde PostgreSQL

Fonctionnalitépg_dump (logique)pg_basebackup (physique)Snapshot système de fichiers
PérimètreBase individuelleCluster completCluster complet
Restauration cross-versionOuiNon (même version majeure)Non
Restauration sélectiveOui (option -t)NonNon
Récupération ponctuelle (PITR)NonOui (avec WAL)Oui (avec WAL)
Sauvegarde à chaudOui (snapshot cohérent)OuiNécessite fsync/freeze
Taille de la sauvegardePetite (données compressées)Grande (répertoire de données complet)Très grande (disque complet)
Vitesse de sauvegardeLente (lecture via SQL)Rapide (streaming)Très rapide (niveau bloc)
Idéal pourBases individuelles, migrationsDR cluster complet, PITRSnapshots VM/cloud

Utilisez pg_dump pour les sauvegardes quotidiennes de bases individuelles et pour les migrations entre versions de PostgreSQL. Utilisez pg_basebackup lorsque vous avez besoin d’une récupération ponctuelle ou que vous mettez en place une réplication en streaming. Utilisez les snapshots système de fichiers en complément, pas en remplacement — ils sont rapides mais nécessitent une gestion rigoureuse des fichiers WAL.

Automatiser les sauvegardes avec cron

Script de sauvegarde

#!/bin/bash
# /usr/local/bin/pg_backup.sh
# Script de sauvegarde PostgreSQL automatisé

set -euo pipefail

# Configuration
BACKUP_DIR="/var/backups/postgresql"
RETENTION_DAYS=30
PG_USER="postgres"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/pg_backup.log"

# Créer le répertoire de sauvegarde s'il n'existe pas
mkdir -p "$BACKUP_DIR"

# Fonction de journalisation
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

log "Démarrage de la sauvegarde PostgreSQL"

# Exporter les objets globaux (rôles, tablespaces)
pg_dumpall -U "$PG_USER" --globals-only > "$BACKUP_DIR/globals_${TIMESTAMP}.sql" 2>> "$LOG_FILE"
log "Objets globaux exportés"

# Exporter chaque base en format personnalisé
for DB in $(psql -U "$PG_USER" -At -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres'"); do
    DUMP_FILE="$BACKUP_DIR/${DB}_${TIMESTAMP}.dump"
    pg_dump -U "$PG_USER" -Fc -Z 6 "$DB" > "$DUMP_FILE" 2>> "$LOG_FILE"
    SIZE=$(du -h "$DUMP_FILE" | cut -f1)
    log "Base $DB exportée ($SIZE)"
done

# Supprimer les sauvegardes plus anciennes que la durée de rétention
find "$BACKUP_DIR" -name "*.dump" -mtime +${RETENTION_DAYS} -delete
find "$BACKUP_DIR" -name "globals_*.sql" -mtime +${RETENTION_DAYS} -delete
log "Nettoyage des sauvegardes de plus de $RETENTION_DAYS jours effectué"

log "Sauvegarde terminée"
# Rendre le script exécutable
chmod +x /usr/local/bin/pg_backup.sh

# Tester manuellement d'abord
sudo -u postgres /usr/local/bin/pg_backup.sh

Planification cron

# Éditer la crontab de l'utilisateur postgres
sudo crontab -u postgres -e
# Sauvegarde quotidienne à 2h00
0 2 * * * /usr/local/bin/pg_backup.sh

# Sauvegarde complète hebdomadaire le dimanche à 1h00 (conservation plus longue)
0 1 * * 0 /usr/local/bin/pg_backup.sh

Authentification sans mot de passe avec .pgpass

Pour les tâches cron, vous avez besoin d’une authentification sans mot de passe. Créez un fichier .pgpass :

# Créer .pgpass pour l'utilisateur postgres
sudo -u postgres bash -c 'cat > ~/.pgpass << EOF
localhost:5432:*:postgres:your_secure_password
EOF'

# Définir les permissions requises (pg_dump refuse d'utiliser un .pgpass lisible par tous)
sudo -u postgres chmod 600 ~/.pgpass

Format : hostname:port:database:username:password. Utilisez * comme joker pour le champ base de données afin de couvrir toutes les bases.

Tester l’intégrité des sauvegardes

Une sauvegarde qui ne peut pas être restaurée n’est pas une sauvegarde. Planifiez des tests de restauration réguliers :

#!/bin/bash
# /usr/local/bin/pg_restore_test.sh
# Vérifier l'intégrité d'une sauvegarde en la restaurant dans une base temporaire

set -euo pipefail

BACKUP_FILE="$1"
TEST_DB="restore_test_$(date +%s)"
PG_USER="postgres"

# Créer la base temporaire
createdb -U "$PG_USER" "$TEST_DB"

# Tenter la restauration
if pg_restore -U "$PG_USER" -d "$TEST_DB" "$BACKUP_FILE" 2>/dev/null; then
    # Vérifier les données
    TABLES=$(psql -U "$PG_USER" -At -c "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public'" "$TEST_DB")
    ROWS=$(psql -U "$PG_USER" -At -c "SELECT sum(n_live_tup) FROM pg_stat_user_tables" "$TEST_DB")
    echo "SUCCÈS : $TABLES tables restaurées avec $ROWS lignes au total"
else
    echo "ÉCHEC : La restauration a rencontré des erreurs"
fi

# Nettoyage
dropdb -U "$PG_USER" "$TEST_DB"
# Tester la sauvegarde la plus récente
sudo -u postgres /usr/local/bin/pg_restore_test.sh /var/backups/postgresql/mydb_latest.dump

Résolution de Problèmes Courants

”pg_dump: error: connection to server failed"

# Vérifier que PostgreSQL est en cours d'exécution
sudo systemctl status postgresql

# Vérifier que la connexion fonctionne
psql -U postgres -h localhost -l

# Consulter pg_hba.conf pour les règles d'authentification
sudo cat /etc/postgresql/16/main/pg_hba.conf | grep -v '^#' | grep -v '^$'

"pg_restore: error: could not execute query: ERROR: relation already exists”

La base cible contient déjà des objets. Utilisez --clean --if-exists pour supprimer les objets existants avant la restauration :

pg_restore -U postgres -d mydb --clean --if-exists mydb_backup.dump

Ou restaurez dans une base vide fraîchement créée :

dropdb -U postgres mydb
createdb -U postgres mydb
pg_restore -U postgres -d mydb mydb_backup.dump

La sauvegarde est trop lente

# Utiliser le dump parallèle (format custom ou directory uniquement)
pg_dump -U postgres -Fd -j $(nproc) -f /backup/mydb_dir mydb

# Exclure les grandes tables régénérables
pg_dump -U postgres -Fc -T large_cache_table -T session_data mydb > mydb.dump

# Réduire la compression pour gagner en vitesse
pg_dump -U postgres -Fc -Z 1 mydb > mydb_fast.dump

La restauration est trop lente

# Utiliser la restauration parallèle (format custom ou directory)
pg_restore -U postgres -d mydb -j $(nproc) mydb_backup.dump

# Désactiver les triggers pendant le chargement des données (gain de vitesse significatif)
pg_restore -U postgres -d mydb --disable-triggers mydb_backup.dump

# Augmenter maintenance_work_mem pour la session de restauration
psql -U postgres -d mydb -c "SET maintenance_work_mem = '1GB';"
pg_restore -U postgres -d mydb mydb_backup.dump

Le fichier .pgpass est ignoré

# Vérifier les permissions (doivent être 600)
ls -la ~/.pgpass

# Corriger les permissions
chmod 600 ~/.pgpass

# Vérifier le format (pas d'espaces superflus)
cat ~/.pgpass
# Doit être : hostname:port:database:username:password

Cas particuliers et pièges à éviter

Grands objets (BLOBs) : pg_dump inclut les grands objets par défaut, mais pg_restore -t ne les restaure PAS. Utilisez pg_restore -L avec une liste personnalisée pour inclure les grands objets lors des restaurations sélectives.

Extensions : pg_dump inclut les instructions CREATE EXTENSION, mais la restauration échoue si l’extension n’est pas installée sur le serveur cible. Installez les extensions avant de restaurer.

Propriété et permissions : pg_dump enregistre la propriété des objets. Si le rôle propriétaire n’existe pas sur le serveur cible, la restauration échoue. Utilisez --no-owner pour ignorer les assignations de propriété, ou créez les rôles au préalable à l’aide du dump des objets globaux.

Accès concurrent pendant le dump : pg_dump prend un snapshot au départ et lit de façon cohérente depuis celui-ci. Les autres transactions continuent normalement. Cependant, les opérations DDL (ALTER TABLE, DROP) maintenant un AccessExclusiveLock bloquent le dump. Planifiez les sauvegardes pendant les périodes de faible activité.

Incompatibilité d’encodage : Si les bases source et cible utilisent des encodages différents, des corruptions de données peuvent survenir. Vérifiez toujours que les encodages correspondent :

psql -U postgres -c "SHOW server_encoding;"

Résumé

  • pg_dump avec le format personnalisé (-Fc) est l’approche recommandée pour les sauvegardes en production — il compresse les données, prend en charge la restauration parallèle et permet la récupération sélective de tables
  • pg_dumpall capture les objets globaux (rôles, tablespaces) que pg_dump ne prend pas en charge — exportez toujours les objets globaux séparément en complément de vos sauvegardes de bases
  • Automatisez avec cron et un script de sauvegarde incluant rotation, journalisation et gestion des erreurs — ne comptez jamais sur des procédures manuelles
  • Testez vos restaurations régulièrement en restaurant vers une base temporaire et en validant les comptages de lignes — une sauvegarde jamais testée est une sauvegarde susceptible d’échouer au moment critique
  • Utilisez .pgpass pour l’authentification sans mot de passe dans les tâches cron avec des permissions chmod 600 — pg_dump refuse de lire les fichiers d’identifiants lisibles par tous
  • Le dump et la restauration parallèles (option -j) réduisent considérablement le temps pour les grandes bases — utilisez le format répertoire (-Fd) pour de meilleures performances parallèles

Articles connexes