The "DB::Exception: Cannot create database" error means ClickHouse was unable to complete a CREATE DATABASE operation. Tagged with the error code CANNOT_CREATE_DATABASE, this is a general failure that can stem from filesystem permissions, disk space issues, invalid database engine parameters, or metadata directory conflicts.
Impact
No database is created, and any subsequent operations that depend on it -- table creation, data ingestion, application queries -- will also fail. In automated deployments, this can block the entire initialization sequence.
Common Causes
- Filesystem permission issues -- the ClickHouse server process does not have write access to the metadata or data directories.
- Insufficient disk space -- no room to create the database's metadata directory.
- Invalid database engine parameters -- providing incorrect arguments to engines like
ReplicatedorMaterializedMySQL. - Metadata directory already exists on disk -- a leftover directory from a previously dropped database that was not fully cleaned up.
- ZooKeeper path conflicts -- for
Replicateddatabase engine, the ZooKeeper path is already in use by another database. - Invalid database name -- names containing special characters or reserved words.
Troubleshooting and Resolution Steps
Read the full error message carefully. ClickHouse usually provides additional context after the main error:
DB::Exception: Cannot create database: directory already exists: /var/lib/clickhouse/metadata/my_databaseCheck filesystem permissions:
ls -la /var/lib/clickhouse/metadata/ ls -la /var/lib/clickhouse/data/The ClickHouse server user (typically
clickhouse) needs write access to both directories.Check available disk space:
df -h /var/lib/clickhouse/Remove leftover metadata directories if a previous drop was incomplete:
# Only after confirming the database should not exist rm -rf /var/lib/clickhouse/metadata/my_database rm -rf /var/lib/clickhouse/data/my_databaseThen restart ClickHouse or retry the CREATE DATABASE.
For Replicated database engine, check ZooKeeper paths:
CREATE DATABASE my_database ENGINE = Replicated('/clickhouse/databases/my_database', '{shard}', '{replica}');Make sure the ZooKeeper path is not already used by another database. Inspect it with:
SELECT * FROM system.zookeeper WHERE path = '/clickhouse/databases/my_database';Verify the database name is valid. Avoid special characters. If you must use unusual names, quote them with backticks:
CREATE DATABASE `my-database`;Check ClickHouse server logs for detailed error information:
tail -50 /var/log/clickhouse-server/clickhouse-server.err.log
Best Practices
- Ensure consistent filesystem permissions across all ClickHouse nodes, especially after OS upgrades or container rebuilds.
- Monitor disk space on ClickHouse data volumes proactively.
- When using the Replicated database engine, establish a clear ZooKeeper path naming convention to avoid conflicts.
- After dropping databases, verify cleanup completed by checking both
system.databasesand the filesystem. - Use simple, lowercase database names without special characters to avoid quoting issues.
Frequently Asked Questions
Q: I see "directory already exists" in the error. Is it safe to remove the directory?
A: Only if you are certain the database should not exist. Check system.databases first. If the database is not listed there but the directory remains, it is a leftover from an incomplete drop and can be safely removed.
Q: Can filesystem permission issues appear suddenly?
A: Yes, especially after container restarts, volume remounts, or OS-level security policy changes (SELinux, AppArmor). Always check permissions as part of your troubleshooting.
Q: What database engines are available in ClickHouse?
A: The main database engines are Atomic (default since 20.5), Ordinary (legacy), Replicated, MaterializedMySQL, MaterializedPostgreSQL, and Lazy. Query SELECT name, engine FROM system.databases to see what your instance uses.
Q: How do I move a database to a different disk?
A: ClickHouse does not support moving databases directly. You would need to create a new database on the target disk (using storage policies), migrate tables with INSERT INTO ... SELECT, and then drop the original.