clickhouse-backup freezes parts instead of reading them
Tool for easy backup and restore for ClickHouse® using object storage for backup files.
At a glance
- What is it?
- Altinity's clickhouse-backup is a Go CLI and API server that backs up ClickHouse tables by hard linking frozen data parts rather than exporting rows, and it insists on running next to clickhouse-server. Good fit for MergeTree clusters with object storage; not usable as a remote backup agent.
- Who is it for?
- Take it if you run MergeTree family tables, need incremental backups in S3, GCS, Azure or via rclone and restic, and can place the binary in the same pod or on the same host as clickhouse-server. Leave it alone if your data lives in non MergeTree engines, if you need a backup agent that runs from a separate machine, or if you rely on ClickHouse's own embedded backup and restore.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The binary has to sit on the same host as the server
The README opens with a warning rather than a feature list: do not run clickhouse-backup remotely. Because the tool needs access to the same files as clickhouse-server in the /var/lib/clickhouse folders, it has to run on the same host, the same Kubernetes Pod, or a neighbor container on that host. When connected to a remote clickhouse-server, the only thing you can back up is schema.
That constraint drives nearly every design decision in the tool. It is not a logical dump utility that speaks SQL and streams rows. It operates on the storage layer, and it needs to be where that storage is.
Supported engines are narrow in the same way. The README lists ClickHouse above 1.1.54394 as supported, and only MergeTree family table engines, with more table types available for clickhouse-server 22.7 and later when USE_EMBEDDED_BACKUP_RESTORE=true. Atomic and Replicated database engines are on the supported list, as are multi disk installations and custom SQL disks declared as SETTINGS disk = disk(...), which the README says works on ClickHouse 23.2+ and is tested from 24.8.
The last push was on 2026-10-14. The most recent tagged release is v2.8.1 from 2026-09-17.
Hard links to frozen parts, not an export
The mechanism is short enough to state precisely. ClickHouse data files are immutable in clickhouse-server. A backup runs ALTER TABLE ... FREEZE, which produces filesystem hard links to the existing data parts. A restore copies those hard links into the detached folder and runs ALTER TABLE ... ATTACH PART for each data part and each table in the backup.
The consequences follow from that design. A backup costs almost no disk read on the ClickHouse side, because the server is not re-serialising rows; it costs disk space in the same filesystem, because the frozen shadow holds hard links until it is uploaded and unfrozen. A restore is a file operation plus an attach, not an INSERT, so the restored table appears with its parts intact rather than being rewritten.
What this buys is speed and fidelity to the on-disk layout. What it costs is that the tool is bound to one filesystem and one server version's storage conventions. The README links a recorded walkthrough of the mechanism rather than documenting the sequence in prose, so the DDL above is the extent of the written description.
Storage targets, including the ones you plug in yourself
Backups live in local directories and can be shipped to remote storage. The README names AWS, GCS, Azure, Tencent COS, FTP and SFTP as built in, and it lists custom remote storage types via rclone, kopia, restic and rsync. Incremental backups on remote storage are supported, which is the part that matters at scale: a second run does not re-upload every part.
Storage settings arrive as environment variables in the documented Docker invocation, using the S3_ prefix. Credentials and bucket are passed in rather than written to a config file, which suits Kubernetes secrets and is awkward for a long lived systemd unit.
Logging follows the same split of concerns. All log messages go to stderr, and stdout carries only command output such as list, tables and print-config, so it can be piped into another tool. The README shows the pipe case with jq, and shows the file case by redirecting both streams.
clickhouse-backup create_remote my_backup >> clickhouse-backup.log 2>&1If you run commands with docker exec or kubectl exec, the README warns the log stays in the exec session rather than the container log. To see it in docker logs or kubectl logs, start the work through the HTTP API instead, for example POST /backup/create_remote.
Three install routes, one of which needs Go 1.21 or newer
The README documents three ways in, and the choice matters for who owns the version.
Download the release archive from the releases page and decompress it. That is the path with no toolchain requirement.
tar -zxvf clickhouse-backup.tar.gzBuild from source requires Go 1.21 or newer, and the module path is versioned at /v2.
GO111MODULE=on go install github.com/Altinity/clickhouse-backup/v2/cmd/clickhouse-backup@latestThe third route is the official tiny Docker image, which the README wants you to run on a host that already has clickhouse-server. Note the user mapping, the host network, and the bind mount of the data directory: all three exist because of the co-location requirement.
docker run -u $(id -u clickhouse) --rm -it --network host -v "/var/lib/clickhouse:/var/lib/clickhouse" \
-e CLICKHOUSE_PASSWORD="password" \
-e S3_BUCKET="clickhouse-backup" \
-e S3_ACCESS_KEY="access_key" \
-e S3_SECRET_KEY="secret" \
altinity/clickhouse-backup --helpThe Makefile builds deb and rpm packages for amd64 and arm64 and supports a fips target, which is relevant if you have a policy requirement around the toolchain rather than a preference.
What SIGKILL leaves behind, and how freezes.tmp tracks it
Interrupt handling is documented in unusual detail, and the detail is where the real operational risk lives.
For one-shot commands such as create, upload, download, restore, delete, create_remote, restore_remote and watch, the first SIGINT or SIGTERM cancels the running command: it unwinds, removes the shadow directories it froze using FREEZE ... WITH NAME <uuid>, and exits with a non-zero code. A create interrupted this way keeps its incomplete local backup directory, which clean_local_broken or the backups_to_keep_local retention setting removes later. The second signal exits immediately, without waiting for cleanup.
SIGKILL cannot be handled at all. That includes OOM kill and pod eviction. The frozen shadow of whatever table was being processed stays on disk. The mitigation is bookkeeping: every FREEZE is recorded in <backup_name>/freezes.tmp before it is executed, so the next clean, delete local, clean_local_broken or retention run unfreezes it.
In server mode, SIGTERM cancels all running commands the same way POST /backup/kill does, removes their pid files and stops the API server. The Kubernetes note is concrete: set terminationGracePeriodSeconds to cover shadow cleanup of a big table, otherwise the follow-up SIGKILL leaves the shadow for the next clean to handle. SIGHUP reloads the config and restarts the API server, canceling running commands the same way POST /restart does.
A frozen shadow is not a corrupted table, but it is disk space you did not plan for, and it survives the process that created it.
Where ClickHouse's own backup fits instead
The README's support line for MergeTree family engines is conditional: more table types become available for clickhouse-server 22.7 and later with USE_EMBEDDED_BACKUP_RESTORE=true.
By comparison, clickhouse-backup is an external process that freezes parts, creates hard links, uploads backups and attaches parts during restore. The external tool gains rclone, kopia, restic and rsync as destinations and gains incremental remote backups; it also inherits the hard constraint that it must sit beside the data.
For a small cluster on one machine with no object storage budget, that trade can go either way. For a cluster where parts must reach a bucket that outlives the node, freezing and linking is the argument for using this project at all.
Editorial conclusion
Take it if you run MergeTree family tables, need incremental backups in S3, GCS, Azure or via rclone and restic, and can place the binary in the same pod or on the same host as clickhouse-server. Leave it alone if your data lives in non MergeTree engines, if you need a backup agent that runs from a separate machine, or if you rely on ClickHouse's own embedded backup and restore. Verify first that your tables are in the supported engine set and that the pod has write access to /var/lib/clickhouse, then reconcile the freeze bookkeeping in freezes.tmp before you trust a first restore.
Frequently asked questions
Can clickhouse-backup run against a remote ClickHouse server?
Only for schema. The README warns not to run the tool remotely, because it needs the same files as clickhouse-server in the /var/lib/clickhouse folders, so it must run on the same host, the same Kubernetes Pod, or a neighbor container on that host.
Which table engines does clickhouse-backup support?
Only MergeTree family engines by default. The README states that more table types are supported for clickhouse-server 22.7 and later with USE_EMBEDDED_BACKUP_RESTORE=true, and that ClickHouse above 1.1.54394 is supported.
Where can clickhouse-backup send backups?
The README lists AWS, GCS, Azure, Tencent COS, FTP and SFTP, plus custom remote storage types through rclone, kopia, restic and rsync. Incremental backups on remote storage are supported.
What happens if clickhouse-backup is killed with SIGKILL?
The signal cannot be handled, so the frozen shadow of the table being processed stays behind. Every FREEZE is written to <backup_name>/freezes.tmp before execution, so a later clean, delete local, clean_local_broken or retention run unfreezes it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/altinity-clickhouse-backup)Was this useful?