Skip to content

Restore Backup

The Restore Backup feature in ClusterControl restores a previously created backup back onto its source cluster, to recover from data loss, corruption, or a bad transaction.

There are two ways to use a backup once it exists:

  • Restore it onto the cluster it came from, to recover the cluster itself. This page covers that flow.
  • Restore it onto a standalone host outside the cluster to confirm it is recoverable, without touching production. See Backup Verification.

Restoring can also undo a bad transaction or operation via point-in-time recovery (PITR), or serve as the starting point for testing and cloning environments. See Create Cluster from Backup to build a brand-new cluster from an existing backup instead of restoring in place.

Restoring only works on backups created using a ClusterControl-supported backup method, and only back onto the cluster where the backup originated. For backups taken outside of ClusterControl (not using a supported backup method), see Restore External Backup; that flow currently only supports MySQL Replication and MySQL Galera clusters.

Supported backup methods

Restore Backup supports every method listed in Supported backup methods, including binlog-chained backups when restoring with PITR.

Prerequisites

Before restoring a backup in ClusterControl, ensure that your environment meets the necessary requirements:

  • The backup must have completed successfully and have been created using ClusterControl. Failed or incomplete backups cannot be restored.
  • Sufficient disk space on the target node for both the restored data and the temporary directory used during restore.
  • Network connectivity between the ClusterControl controller and the source cluster where the backup is stored.
  • Appropriate user permissions and privileges on the target node. If SELinux or AppArmor is enabled, ensure it is configured to allow the restore operation to complete.
  • The cluster's topology should be otherwise healthy going into the restore. Restoring is meant to recover from a failure, not to fix an already-unstable topology; nodes that are down should come back to a normal state once the restore finishes.

Warning

Restoring a backup overwrites the existing data on the target node. Make sure you have selected the correct backup and target before confirming the restore.


Restoring vs. Verifying

The How to restore wizard step (see Common Wizard Steps below) offers two paths:

  • Restore on node: Restores the backup in place, onto a node in the source cluster. This is the recovery path covered on this page.
  • Restore and verify on standalone host: Restores the backup onto a separate Backup Verification Server (BVS) outside the cluster instead, to confirm it is recoverable without touching production. This path is fully covered in Backup Verification and is not duplicated here.

This choice is only offered for methods that support backup verification: mysqldump, xtrabackup, mariabackup, pgdumpall, pgdump, pg_basebackup, pgbackrest, and rdb (Redis Sentinel only). For MongoDB, SQL Server, and Elasticsearch, the wizard goes straight from Configuration to Settings since there is no standalone-host verification path for these methods.


Point-in-Time Recovery (PITR)

Point-in-time recovery lets you restore a database to any moment between a backup and the present, rather than only to the exact point the backup was taken. Instead of accepting data loss back to the last full backup, you can replay the transaction log forward to just before the bad event, such as a dropped table, a botched UPDATE, or an accidental DELETE, and stop there.

Supported databases and backup methods

Database Backup method PITR mechanism Stop point
MySQL & Percona mysqldump (Complete type) Binary log replay on restore target Timestamp or binlog position
MariaDB mysqldump or mariadb-dump (Complete type, depending on version) Binary log replay on restore target Timestamp or binlog position
MySQL & Percona xtrabackupfull / xtrabackupincr Binary log replay on restore target Timestamp or binlog position
MariaDB mariabackupfull / mariabackupincr Binary log replay on restore target Timestamp or binlog position
PostgreSQL & TimescaleDB pg_basebackup / pg_basebackupincr WAL replay (requires WAL archiving enabled) Timestamp
PostgreSQL & TimescaleDB pgbackrestfull / pgbackrestdiff / pgbackrestincr WAL replay (archiving managed by pgbackrest) Timestamp

PITR is not available for pgdumpall, pgdump, MongoDB, Redis & Valkey, or Elasticsearch.

SQL Server transaction log restores

SQL Server supports point-in-time recovery through its native backup chain: a full backup (mssqlfull) chained with differential (mssqldiff) and transaction log (mssqllog) backups. In the restore wizard, you select which log backup to restore up to. This is handled through chain selection rather than a freeform timestamp, and is described in the SQL Server section below.

Setup requirements

MySQL & MariaDB

PITR requires a full backup taken with a PITR-compatible method: mysqldump/mariadb-dump with dump type Complete, xtrabackupfull/xtrabackupincr, or mariabackupfull/mariabackupincr. During restore, ClusterControl replays binary logs up to the specified stop time or position.

  • Without a scheduled binlog backup: ClusterControl replays the binary logs directly from the restore target server. They must still be present and unmodified on the target node at the time of restore. If they have been purged or rotated away, the PITR window shrinks or disappears entirely.
  • With a scheduled binlog backup (cloud only): ClusterControl downloads the archived binary logs from cloud storage and replays them first, then replays the latest binary log still present on the restore target server to reach the stop point. This extends the PITR window beyond what local binary log retention alone would allow. See Schedule Backup for setting up a binlog backup.

Warning

Without a scheduled binlog backup, PITR availability depends entirely on binary log retention on the restore target. Ensure expire_logs_days (MySQL) or binlog_expire_logs_seconds is set to cover your intended recovery window.

PostgreSQL

For pg_basebackup and pg_basebackupincr, WAL archiving must be enabled on the PostgreSQL server (archive_mode = on with a configured archive_command). During restore, ClusterControl restores the base backup, stops the PostgreSQL server, configures the PITR recovery parameters and recovery mode, then starts the server so PostgreSQL replays the archived WAL segments to reach the requested recovery point.

pgbackrest manages WAL archiving automatically as part of its backup process, so no separate WAL configuration is needed. The earliest allowed recovery point for pgbackrest is the backup creation time, or the current time minus the PITR_RETENTION_HOURS setting, whichever is more recent.

Operational notes

  • The recovery target must be after the backup's creation time. You cannot replay backward past the backup itself.
  • For MySQL & MariaDB, choose Time or Position:
    • Time: Stops binlog replay at a specific date and time in the host's timezone. Use this when you know roughly when the problem occurred.
    • Position: Stops at an exact binlog file and byte offset. Use this when you have identified the exact transaction to stop before (for example, from mysqlbinlog output).
  • After PITR restore, replicas must be rebuilt. The primary will be at a different point in the transaction history than the replicas. ClusterControl will resync replicas from the restored primary as part of the restore job, but verify the topology is healthy before resuming writes.
  • The backup must remain available. If the backup was stored only locally and the local copy has been deleted, or if cloud download fails, the restore job will not start.
  • Test PITR regularly. Run PITR restores against a Backup Verification host to confirm that binary logs or WAL archives are intact and cover the expected recovery window before you need it in production.

Common Wizard Steps

The restore wizard follows the same flow for every database type, though the How to restore step and some Settings fields are skipped for methods that don't support them (noted inline where that applies).

Opening the wizard

  1. Go to the Clusters dashboard and click your target cluster.
  2. Go to the Backups tab, keeping the view set to All Backups (default).
  3. Click the action menu (...) on the backup you want to restore and select Restore.

Step 1: Configuration

  • Backup: The backup selected for restore.
  • Incremental backups: Only shown for backups that have incrementals chained to them (xtrabackup, mariabackup, pg_basebackupincr, or a full SQL Server backup with differential/log backups chained to it). Lists the available incremental backups linked to the selected full backup.
  • Restore this backup from: The storage path or location of the backup.
  • Method: Read-only panel showing the backup method, size, creation time, and the host where it was taken.

Click Continue.


Step 2: How to restore

Only shown for methods that support backup verification (see Restoring vs. Verifying above).

  • Restore on node: Restores the backup onto the source cluster, to recover it. Select this option for the recovery flow covered on this page.
  • Restore and verify on standalone host: Restores the backup to an external Backup Verification Server instead. See Backup Verification.

Click Continue.


Step 3: Settings

Fields vary by backup method; see Database-Specific Settings below for the exact fields shown for each method.

Click Continue.


Step 4: Summary

Review the selected backup and restore options. This is the final confirmation before ClusterControl restores the backup. Click Finish to run the job.

Restores use s9s backup --restore with --cluster-id and --backup-id, plus --wait --log to print job progress while it runs.

  • Restore backup ID 3 on cluster ID 2:

    s9s backup \
        --restore \
        --cluster-id=2 \
        --backup-id=3 \
        --wait \
        --log
    

    If the backup is encrypted, it is automatically decrypted during restore.

Method-specific flags (--memory, --pitr-stop-time, --psql-immediate) are listed in each database section below.

"Restore and verify on standalone host" has no CLI equivalent under --restore. Use s9s backup --verify --backup-id=<ID> --test-server=<HOST> --cluster-id=<ID> instead, which restores the backup to the given host to confirm it is recoverable. See Backup Verification.

Restore Backup does not have a dedicated convenience operation. A restore job is created through the generic createJobInstance call on POST /v2/jobs, with job.job_spec.command set to restore. All calls require a TLS connection and, in most cases, an authenticated session or inline credentials. See ClusterControl RPC API → Authenticating with the API for details.

  • Restore backup ID 3 on cluster ID 2:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 2,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 3
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

Database-Specific Settings

Each section below covers the Settings step fields unique to that database type, plus CLI and RPC API examples.

MySQL & MariaDB

Covers MySQL & Percona & MariaDB standalone and primary-replica replication clusters, as well as Galera Cluster topologies (Percona XtraDB Cluster, MariaDB Galera Cluster). The Settings fields are identical across topologies; only the cluster you target differs.

mysqldump - unique Settings

  • Restore backup on: Defaults to the primary node. Select a replica instead if you only need to recover or inspect data outside the primary (for example, checking dropped data), rather than bring the whole cluster back to health.
  • Temporary directory: Staging area for the backup files during restore. Must have enough free space to hold a full copy of the datadir.
  • Restore system database: Defaults to Off. Turn On to also restore MySQL's system database, mysql. Leave this off if your existing data directory isn't corrupted and you only need to restore user data for testing or verification.
  • Bootstrap cluster from restored node: Defaults to On. Starts the restored node first so the rest of the cluster bootstraps from it, avoiding data drift between nodes.
  • Point in time recovery (PITR): Defaults to Off. Only shown for PITR-compatible mysqldump backups. When On, choose one of:
    • Time: Set Restore time in host TZ to stop replaying binary logs at a specific date and time.
    • Position: Set Binary log name and Log stop position to stop replaying at an exact binlog coordinate instead of a timestamp.

xtrabackup / mariabackup - unique Settings

  • Incremental backups: Only shown when the selected full backup (xtrabackupfull or mariabackupfull) has incremental backups chained to it. Select which incremental to restore up to.
  • Restore backup on: Same behavior as mysqldump above.
  • Temporary directory: Same behavior as mysqldump above.
  • xtrabackup --use-memory (MiB): xtrabackup only. Memory allocated for the xtrabackup --prepare step, analogous to innodb_buffer_pool_size. Defaults to 100 MiB; 1024-2048 MiB is a reasonable value if you have the memory available.
  • Make a copy of the datadir before restoring the backup: mariabackup only. Defaults to Off. Turn On to keep a copy of the current datadir before it's replaced, in case you need to fall back.
  • Bootstrap cluster from restored node: Same behavior as mysqldump above.
  • Point in time recovery (PITR): Available for xtrabackup and mariabackup. Same Time/Position behavior as mysqldump above.
  • Restore a full backup:

    s9s backup \
        --restore \
        --cluster-id=127 \
        --backup-id=3 \
        --wait \
        --log
    

    Works for mysqldump, xtrabackupfull, and mariabackupfull backups the same way. If the backup has chained incrementals, ClusterControl restores the full chain automatically.

  • Restore an xtrabackup with a custom memory allocation for the prepare step:

    s9s backup \
        --restore \
        --cluster-id=99 \
        --backup-id=12 \
        --memory=2048 \
        --wait \
        --log
    
  • Restore using a custom temporary directory to stage the backup files, if the default staging path doesn't have enough free space:

    s9s backup \
        --restore \
        --cluster-id=99 \
        --backup-id=12 \
        --temp-dir-path=/data/restore-tmp \
        --wait \
        --log
    
  • Restore a PITR-compatible mysqldump or mariabackup backup up to a specific timestamp:

    s9s backup \
        --restore \
        --cluster-id=127 \
        --backup-id=3 \
        --pitr-stop-time="2020-07-14 14:27:04" \
        --log
    

    --pitr-stop-time requires binlog backups to be scheduled alongside the PITR-compatible full backup; see Schedule Backup → Binlog backup for setup.

"Restore system database", "Make a copy of the datadir before restoring", and "Bootstrap cluster from restored node" have no dedicated CLI flags; the CLI restore follows ClusterControl's default behavior for these (bootstrap on, system database and datadir copy off).

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a full backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 127,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 3
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    
  • Restore an xtrabackup with a custom memory allocation:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 99,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 12,
                    "memory": 2048
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    
  • Restore using a custom temporary directory to stage the backup files:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 99,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 12,
                    "temp_dir_path": "/data/restore-tmp"
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    
  • Restore a PITR-compatible backup up to a specific timestamp:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 127,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 3,
                    "pitr_stop_time": "2020-07-14 14:27:04"
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

PostgreSQL & TimescaleDB

  • Restore backup on: Disabled; always restores to the primary node.
  • Incremental backups: Only shown for pg_basebackupincr backups with a chain. ClusterControl reconstructs the full chain automatically using pg_combinebackup.
  • Make a copy of the datadir before restoring the backup: pgbackrest only. Defaults to Off. Turn On to keep a copy of the current datadir before it's replaced.
  • Point in time recovery (PITR): Available for pg_basebackup/pg_basebackupincr (when WAL archiving is enabled) and all pgbackrest methods. Defaults to Off. When On, set Restore Time to how far PostgreSQL should replay forward. For pgbackrest, the earliest allowed value is either the backup's creation time, or the current time minus the PITR_RETENTION_HOURS setting (whichever is more recent, if that setting is greater than 1 hour).
  • Bootstrap cluster from restored node: Defaults to On. Starts the restored node first so the rest of the cluster bootstraps from it.
  • Restore a backup:

    s9s backup \
        --restore \
        --cluster-id=125 \
        --backup-id=8 \
        --wait \
        --log
    

    Works for pgdumpall, pgdump, pg_basebackup, pg_basebackupincr, and pgbackrestfull/pgbackrestdiff/pgbackrestincr the same way.

  • Restore without replaying the full WAL stream (finish recovery as soon as consistency is reached):

    s9s backup \
        --restore \
        --cluster-id=125 \
        --backup-id=8 \
        --psql-immediate \
        --log
    
  • Restore a pgbackrest backup up to a specific point in time:

    s9s backup \
        --restore \
        --cluster-id=125 \
        --backup-id=8 \
        --pitr-stop-time="2020-07-14 14:27:04" \
        --log
    

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 125,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 8
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    
  • Restore without replaying the full WAL stream:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 125,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 8,
                    "psql_immediate": true
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

MongoDB

MongoDB Replica Set and Sharded Cluster restores each accept only the method used to create the backup: mongodump for Replica Set, percona-backup-mongodb (PBM) for Sharded Cluster.

mongodump (Replica Set)

No Settings step. After Configuration, click Finish to restore.

percona-backup-mongodb (Sharded Cluster)

  • Make a copy of the datadir before restoring the backup: Defaults to Off. Turn On to keep a copy of the current datadir before it's replaced.
  • Restore a mongodump backup:

    s9s backup \
        --restore \
        --cluster-id=79 \
        --backup-id=5 \
        --wait \
        --log
    
  • Restore a percona-backup-mongodb backup:

    s9s backup \
        --restore \
        --cluster-id=28 \
        --backup-id=9 \
        --wait \
        --log
    

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 79,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 5
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

    The same shape works for percona-backup-mongodb backups; only cluster_id and backup_id change.


Redis & Valkey

Applies to Redis and Valkey, in both Sentinel and Cluster topologies.

Sentinel

  • How to restore step is shown (see Restoring vs. Verifying).
  • Restore backup on: Disabled; always restores to the primary node.
  • Make a copy of the datadir before restoring the backup: Defaults to Off. Turn On to keep a copy of the current datadir before it's replaced.

Cluster

  • No How to restore step; backup verification is not supported for Cluster mode.
  • Restore backup on: Disabled; always restores to the primary node.
  • Make a copy of the datadir before restoring the backup: Same as Sentinel above.
  • Restore a backup:

    s9s backup \
        --restore \
        --cluster-id=84 \
        --backup-id=6 \
        --wait \
        --log
    

    Works the same way for both Sentinel and Cluster topologies.

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 84,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 6
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

SQL Server

  • Incremental backups: Only shown when the selected mssqlfull backup has differential or transaction log backups chained to it. Select which one to restore up to.
  • No How to restore or Settings step; backup verification is not supported for SQL Server. After Configuration, click Finish to restore.
  • Restore a full backup:

    s9s backup \
        --restore \
        --cluster-id=42 \
        --backup-id=15 \
        --wait \
        --log
    

    To restore up to a differential or transaction log backup, pass that backup's ID instead; ClusterControl restores the full backup it is chained to first.

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 42,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 15
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs
    

Elasticsearch

  • No How to restore step; Elasticsearch verifies snapshots via the Elasticsearch snapshot API instead of a standalone host restore. See Backup Verification → Elasticsearch for that flow.
  • Make a copy of the datadir before restoring the backup: Defaults to Off. Turn On to keep a copy of the current datadir before it's replaced.
  • Restore a backup:

    s9s backup \
        --restore \
        --cluster-id=8 \
        --backup-id=4 \
        --wait \
        --log
    

All calls go to POST https://<CONTROLLER_HOST>:9501/v2/jobs.

  • Restore a backup:

    curl -k -XPOST \
    -d '{
        "operation": "createJobInstance",
        "cluster_id": 8,
        "job": {
            "class_name": "CmonJobInstance",
            "job_spec": {
                "command": "restore",
                "job_data": {
                    "backup_id": 4
                }
            }
        }
    }' \
    -b cookies.jar \
    https://localhost:9501/v2/jobs