This guide covers all restore scenarios: full restore, partial restore, table renaming, database remapping, and troubleshooting.
- How restore works
- Basic restore
- Restore from S3 (restore_remote)
- Mode A: destructive restore (--rm)
- Mode B: non-destructive restore (default)
- Table filtering
- Table rename (--as)
- Database remap (-m)
- Partition filtering
- Schema only / Data only
- RBAC and config restore
- Resuming interrupted restores
- Replicated tables
- ON CLUSTER restore
- Troubleshooting
A restore follows these steps:
- Read the backup manifest (
metadata.json) - Phase 0 (Mode A only): DROP existing tables and databases
- Create databases (if they do not exist)
- Create tables (DDL from the backup)
- For each table, attach data parts:
- Local disk parts: hardlink files from backup to
detached/directory, thenALTER TABLE ATTACH PART - S3 disk parts: CopyObject in S3 to the table's UUID path, rewrite metadata, then
ALTER TABLE ATTACH PART
- Local disk parts: hardlink files from backup to
- Re-apply pending mutations (if any were captured during backup)
- Fix file ownership (
chownto ClickHouse user)
Restore a local backup (already downloaded):
chbackup restore my-backupThis uses Mode B (non-destructive): it creates tables if they do not exist and attaches data. Existing data in existing tables is preserved.
Download and restore in one step:
chbackup restore_remote my-backupThis is equivalent to running chbackup download my-backup followed by chbackup restore my-backup.
Use latest to restore the most recent remote backup:
chbackup restore_remote latestDrops existing tables and databases before restoring. The restored state will match the backup exactly.
chbackup restore --rm my-backup
chbackup restore_remote --rm my-backupWhat happens:
- All tables in the backup are dropped (if they exist in ClickHouse)
- Databases are dropped if they become empty
- Databases and tables are recreated from backup DDL
- Data parts are attached
System databases (system, INFORMATION_SCHEMA, information_schema) are never dropped.
Use Mode A when:
- You want to roll back to an exact point in time
- You are migrating to a new server and want a clean slate
- Schema has changed and you need to match the backup exactly
The default mode. Does not drop anything. Creates databases and tables only if they do not exist, then attaches data parts.
chbackup restore my-backupIf a table already exists with data, the backup's data parts are attached alongside existing data. This is additive.
Use Mode B when:
- You want to add missing data without disrupting existing tables
- You are restoring a subset of tables
- You want to test a restore without risk
Restore only specific tables using glob patterns:
# Restore all tables in the default database
chbackup restore -t "default.*" my-backup
# Restore a single table
chbackup restore -t "default.users" my-backup
# Restore multiple specific tables
chbackup restore -t "default.users,default.orders" my-backup
# Restore all tables matching a pattern
chbackup restore -t "*.events" my-backupRestore tables under different names. Useful for testing or side-by-side comparison.
Use -t to select the source table and --as to specify the destination:
chbackup restore -t default.users --as=default.users_restored my-backupThis restores default.users from the backup as default.users_restored.
Use colon-separated pairs:
chbackup restore --as="default.users:default.users_copy,default.orders:default.orders_copy" my-backupEach pair is source_db.source_table:dest_db.dest_table. You can rename to a different database:
chbackup restore --as="production.users:staging.users,production.orders:staging.orders" my-backupMove all tables from one database to another:
chbackup restore -m "production:staging" my-backupThis restores every table from the production database into the staging database instead.
Remap multiple databases:
chbackup restore -m "production:staging,analytics:analytics_test" my-backupCombine with table filter:
# Only restore tables from the production database, into staging
chbackup restore -t "production.*" -m "production:staging" my-backup--asrenames individual tables (one-to-one mapping)-mremaps entire databases (all tables in the source database go to the destination)
Use --as when you need fine-grained control over individual table names. Use -m when you want to move a whole database.
Restore only specific partitions:
# Restore only the January 2024 partition
chbackup restore --partitions="202401" my-backup
# Restore January and February
chbackup restore --partitions="202401,202402" my-backupPartition IDs come from ClickHouse's partition expression. For monthly partitioning (PARTITION BY toYYYYMM(ts)), the IDs are like 202401. For daily (PARTITION BY toYYYYMMDD(ts)), they are like 20240115.
For unpartitioned tables (no PARTITION BY clause or tuple()), use all:
chbackup restore --partitions="all" my-backupWhen using --partitions, some tables may have no matching partitions. Use --skip-empty-tables to skip creating those tables:
chbackup restore --partitions="202401" --skip-empty-tables my-backupWithout this flag, tables with no matching partitions are still created (DDL only, no data).
Restore table definitions (DDL) without data. Useful for setting up a new cluster:
chbackup restore --schema my-backupRestore data parts without running any DDL. Tables must already exist with compatible schemas:
chbackup restore --data-only my-backupThese two flags cannot be used together.
# Step 1: Create tables on the new cluster
chbackup restore --schema my-backup
# Step 2: Modify schemas if needed (add columns, change settings, etc.)
# Step 3: Attach data
chbackup restore --data-only my-backupRestore users, roles, quotas, row policies, and settings profiles:
chbackup restore --rbac my-backupIf an object already exists, the behavior depends on clickhouse.rbac_resolve_conflicts:
recreate(default): DROP and re-CREATE the objectignore: Skip existing objectsfail: Return an error
Restore server config files from the backup:
chbackup restore --configs my-backupAfter restoring configs, ClickHouse needs a restart. chbackup runs the clickhouse.restart_command automatically.
chbackup restore --named-collections my-backupchbackup restore --rbac --configs --named-collections my-backupIf a restore is interrupted (crash, timeout, Ctrl+C), resume from where it left off:
chbackup restore --resume my-backupResume state is tracked per part. Parts that were already attached are skipped. The state file is stored alongside the backup data and is automatically deleted on completion.
Resume works for both restore and restore_remote:
chbackup restore_remote --resume my-backupchbackup handles Replicated tables automatically:
- Before creating the table, it checks ZooKeeper for existing replicas
- If a conflict is found (same replica name), it runs
SYSTEM DROP REPLICAto clean up - Creates the table (which registers the new replica in ZK)
- Attaches data parts
For Replicated tables, an alternative restore mode uses DETACH/ATTACH TABLE instead of per-part ATTACH:
clickhouse:
restore_as_attach: trueThis mode:
- DETACH TABLE SYNC
- DROP REPLICA in ZK
- Hardlink all parts to the table's data directory
- ATTACH TABLE
- SYSTEM RESTORE REPLICA
This can be faster for tables with many parts. It falls back to normal per-part attach on failure. Note: ATTACH TABLE mode does not work for tables stored on S3 disks.
For ClickHouse clusters, execute DDL with ON CLUSTER:
clickhouse:
restore_schema_on_cluster: "my_cluster"This adds ON CLUSTER 'my_cluster' to all CREATE DATABASE and CREATE TABLE statements. DDL is automatically skipped for DatabaseReplicated databases (they handle replication internally).
When restoring to a cluster with a different name:
clickhouse:
restore_distributed_cluster: "new_cluster_name"This rewrites the cluster name in Distributed engine definitions during restore.
In Mode B (default), this is expected -- the table is skipped and data parts are attached to the existing table. If you want a clean restore, use --rm.
If you restore the same backup twice in Mode B, you get duplicate data. Each run attaches new copies of the data parts. Use --rm for idempotent restores, or use --resume if the first restore was interrupted.
The table in ClickHouse has a different schema than the backup. Options:
- Use
--rmto drop and recreate the table with the backup's schema - Manually ALTER the table to match the backup's schema, then
--data-only - Restore to a new table with
--asand merge data manually
- Increase
clickhouse.max_connectionsto restore more tables in parallel - Check if S3 disk CopyObject is the bottleneck (increase
general.object_disk_server_side_copy_concurrency) - For tables with many small parts, the bottleneck is per-part ATTACH overhead
chbackup attempts to resolve ZK conflicts automatically via SYSTEM DROP REPLICA. If this fails:
- Check ZooKeeper connectivity from ClickHouse
- Manually clean up the replica:
SYSTEM DROP REPLICA 'replica_name' FROM TABLE db.table - Retry the restore
chbackup runs chown to fix file ownership after restoring data. If you see permission errors:
- Verify chbackup runs as root or the
clickhouseuser - Check that the ClickHouse user has read access to the data directory
- In Docker, ensure the chbackup container runs with the same UID (101) as ClickHouse