{"id":35500255,"url":"https://github.com/bakwc/mysql_ch_replicator","last_synced_at":"2026-02-05T23:03:14.189Z","repository":{"id":235234258,"uuid":"788861325","full_name":"bakwc/mysql_ch_replicator","owner":"bakwc","description":"Tool for replication of MySQL databases to ClickHouse","archived":false,"fork":false,"pushed_at":"2026-01-15T22:10:23.000Z","size":1222,"stargazers_count":89,"open_issues_count":21,"forks_count":32,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-16T01:44:26.727Z","etag":null,"topics":["clickhouse","database","mysql-clickhouse","replication"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bakwc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-19T08:24:03.000Z","updated_at":"2026-01-15T22:08:13.000Z","dependencies_parsed_at":"2024-04-22T19:27:13.999Z","dependency_job_id":"8f346c4d-2693-4d2f-a858-add192565fb5","html_url":"https://github.com/bakwc/mysql_ch_replicator","commit_stats":null,"previous_names":["bakwc/mysql_ch_replicator"],"tags_count":93,"template":false,"template_full_name":null,"purl":"pkg:github/bakwc/mysql_ch_replicator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakwc%2Fmysql_ch_replicator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakwc%2Fmysql_ch_replicator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakwc%2Fmysql_ch_replicator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakwc%2Fmysql_ch_replicator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bakwc","download_url":"https://codeload.github.com/bakwc/mysql_ch_replicator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakwc%2Fmysql_ch_replicator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29137754,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T23:02:30.544Z","status":"ssl_error","status_checked_at":"2026-02-05T23:02:24.945Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clickhouse","database","mysql-clickhouse","replication"],"created_at":"2026-01-03T18:19:01.952Z","updated_at":"2026-02-05T23:03:14.176Z","avatar_url":"https://github.com/bakwc.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mysql_ch_replicator\n![tests](https://github.com/bakwc/mysql_ch_replicator/actions/workflows/tests.yaml/badge.svg)\n[![Release][release-image]][releases]\n[![License][license-image]][license]\n\n[release-image]: https://img.shields.io/github/v/release/bakwc/mysql_ch_replicator?style=flat\n[releases]: https://github.com/bakwc/mysql_ch_replicator/releases\n\n[license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat\n[license]: LICENSE\n\n![img](https://raw.githubusercontent.com/bakwc/mysql_ch_replicator/master/mysql_ch.jpg)\n\n`mysql_ch_replicator` is a powerful and efficient tool designed for real-time replication of MySQL databases to ClickHouse.\n\nWith a focus on high performance, it utilizes batching heavily and uses C++ extension for faster execution. This tool ensures seamless data integration with support for migrations, schema changes, and correct data management.\n\n## Table of Contents\n- [Features](#features)\n- [Installation](#installation)\n  - [Requirements](#requirements)\n  - [Installation](#installation-1)\n  - [Docker Installation](#docker-installation)\n- [Usage](#usage)\n  - [Basic Usage](#basic-usage)\n  - [One Time Data Copy](#one-time-data-copy)\n  - [Configuration](#configuration)\n    - [Required settings](#required-settings)\n    - [Optional settings](#optional-settings)\n  - [Advanced Features](#advanced-features)\n    - [Cluster Mode](#cluster-mode)\n    - [Migrations \u0026 Schema Changes](#migrations--schema-changes)\n    - [Recovery Without Downtime](#recovery-without-downtime)\n    - [Known Limitations](#known-limitations)\n- [Production usage](#production-usage)\n- [Development](#development)\n  - [Running Tests](#running-tests)\n- [Contribution](#contribution)\n- [License](#license)\n- [Acknowledgements](#acknowledgements)\n\n## Features\n\n- **Real-Time Replication**: Keeps your ClickHouse database in sync with MySQL in real-time.\n- **High Performance**: Utilizes batching and ports slow parts to C++ (e.g., MySQL internal JSON parsing) for optimal performance (±20K events / second on a single core).\n- **Supports Migrations/Schema Changes**: Handles adding, altering, and removing tables without breaking the replication process (*for most cases, [details here](https://github.com/bakwc/mysql_ch_replicator#migrations--schema-changes)).\n- **Recovery without Downtime**: Allows for preserving old data while performing initial replication, ensuring continuous operation.\n- **Correct Data Removal**: Unlike MaterializedMySQL, `mysql_ch_replicator` ensures physical removal of data.\n- **Comprehensive Data Type Support**: Accurately replicates most data types, including JSON, booleans, and more. Easily extensible for additional data types.\n- **Multi-Database Handling**: Replicates the binary log once for all databases, optimizing the process compared to `MaterializedMySQL`, which replicates the log separately for each database.\n\n## Installation\n### Requirements\n - Linux / MacOS\n - python3.10 or higher\n\n### Installation\n\nTo install `mysql_ch_replicator`, use the following command:\n\n```bash\npip install --upgrade mysql_ch_replicator\n```\n\nYou may need to also compile C++ components if they're not pre-built for your platform.\n\n### Docker Installation\n\nAlternatively, you can use the pre-built Docker image from DockerHub:\n\n```bash\ndocker pull fippo/mysql-ch-replicator:latest\n```\n\nTo run the container:\n\n```bash\ndocker run -d \\\n  -v /path/to/your/config.yaml:/app/config.yaml \\\n  -v /path/to/your/data:/app/data \\\n  fippo/mysql-ch-replicator:latest \\\n  --config /app/config.yaml run_all\n```\n\nOr with environment variables for credentials:\n\n```bash\ndocker run -d \\\n  -v /path/to/your/config.yaml:/app/config.yaml \\\n  -v /path/to/your/data:/app/data \\\n  -e MYSQL_USER=root \\\n  -e MYSQL_PASSWORD=secret \\\n  -e CLICKHOUSE_USER=default \\\n  -e CLICKHOUSE_PASSWORD=secret \\\n  fippo/mysql-ch-replicator:latest \\\n  --config /app/config.yaml run_all\n```\n\nMake sure to:\n1. Mount your configuration file using the `-v` flag\n2. Mount a persistent volume for the data directory\n3. Adjust the paths according to your setup\n4. Optionally use `-e` flags to override credentials via environment variables\n5. Adjust Timezone of the docker container `-e TZ=Region/City`. Otherwise `mysql_ch_replicator` might add a positive or negative offest (depending upon where the server is) to Datetime columns which [will lead to incorrect data in clickhouse](https://github.com/bakwc/mysql_ch_replicator/pull/230#issuecomment-3714257840).\n\n## Usage\n\n### Basic Usage\n\nHere is a [video tutorial](https://www.youtube.com/watch?v=pfbw8VzdIz4)\n\nFor realtime data sync from MySQL to ClickHouse:\n\n1. Prepare config file. Use `example_config.yaml` as an example.\n2. Configure MySQL and ClickHouse servers:\n - MySQL server configuration file `my.cnf` should include following settings (required to write binary log in raw format, and enable password authentication):\n\u003cdetails\u003e\n  \u003csummary\u003e🛠 MySQL Config\u003c/summary\u003e\n\n```ini\n[mysqld]\n# ... other settings ...\ngtid_mode = on\nenforce_gtid_consistency = 1\nbinlog_expire_logs_seconds = 864000\nmax_binlog_size            = 500M\nbinlog_format              = ROW\n```\n - For MariaDB use following settings:\n```ini\n[mysqld]\n# ... other settings ...\ngtid_strict_mode = ON\ngtid_domain_id = 0\nserver_id = 1\nlog_bin = /var/log/mysql/mysql-bin.log\nbinlog_expire_logs_seconds = 864000\nmax_binlog_size = 500M\nbinlog_format = ROW\n```\n\nFor `AWS RDS` you need to set following settings in `Parameter groups`:\n\n```\nbinlog_format                       ROW\nbinlog_expire_logs_seconds          86400\n```\n\n\u003c/details\u003e\n\n - ClickHouse server config `override.xml` should include following settings (it makes clickhouse apply final keyword automatically to handle updates correctly):\n\n \u003cdetails\u003e\n   \u003csummary\u003e🛠 ClickHouse Config\u003c/summary\u003e\n \n```xml\n\u003cclickhouse\u003e\n    \u003c!-- ... other settings ... --\u003e\n    \u003cprofiles\u003e\n        \u003cdefault\u003e\n            \u003c!-- ... other settings ... --\u003e\n            \u003cfinal\u003e1\u003c/final\u003e\n            \u003cmax_query_size\u003e300000000\u003c/max_query_size\u003e\n            \u003cmax_ast_elements\u003e1000000\u003c/max_ast_elements\u003e\n            \u003cmax_expanded_ast_elements\u003e1000000\u003c/max_expanded_ast_elements\u003e\n        \u003c/default\u003e\n    \u003c/profiles\u003e\n\u003c/clickhouse\u003e\n```\n\n**!!! Double check final setting is applied !!!**\n\nExecute the following command in clickhouse:\n\n`SELECT name, value, changed FROM system.settings WHERE name = 'final'`\nSetting should be set to 1. If not, you should:\n * double check the `override.xml` is applied\n * try to modify `users.xml` instead\n\u003c/details\u003e\n\n3. Grant following permissions to MySQL user:\n \n  ```bash\n  GRANT SELECT, SUPER, REPLICATION SLAVE ON . TO 'user'@'%' identified by 'password';\n  ```\n\n4. Start the replication:\n\n```bash\nmysql_ch_replicator --config config.yaml run_all\n```\n\nThis will keep data in ClickHouse updating as you update data in MySQL. It will always be in sync.\n\n### One Time Data Copy\n\nIf you just need to copy data once, and don't need continuous synchronization for all changes, you should do following:\n\n1. Prepare config file. Use `example_config.yaml` as an example.\n2. Run one-time data copy:\n\n```bash\nmysql_ch_replicator --config config.yaml db_replicator --db mysql_db_name --initial_only=True\n```\nWhere `mysql_db_name` is the name of the database you want to copy.\n\nDon't be afraid to interrupt process in the middle. It will save the state and continue copy after restart.\n\n__Hint__: _set `initial_replication_threads` to a number of cpu cores to accelerate initial replication_\n\n### Configuration\n\n`mysql_ch_replicator` can be configured through a configuration file and also by using enviromnent variables to override some of config settings. Here is the config example:\n\n```yaml\nmysql:\n  host: 'localhost'\n  port: 8306\n  user: 'root'\n  password: 'root'\n  charset: 'utf8mb4'  # optional, default is utf8mb4 for full Unicode support\n\nclickhouse:\n  host: 'localhost'\n  port: 8323\n  user: 'default'\n  password: 'default'\n  connection_timeout: 30        # optional\n  send_receive_timeout: 300     # optional\n  cluster: 'cluster_name'       # optional - should match cluster name defined in config files located at /etc/clickhouse-server\n\nbinlog_replicator:\n  data_dir: '/home/user/binlog/'  # a new EMPTY directory (for internal storage of data by mysql_ch_replicator itself)\n  records_per_file: 100000\n  binlog_retention_period: 43200  # optional, how long to keep binlog files in seconds, default 12 hours\n\ndatabases: 'database_name_pattern_*'\ntables: '*'\n\n\n# OPTIONAL SETTINGS\n\ninitial_replication_threads: 4                        # optional\n\nexclude_databases: ['database_10', 'database_*_42']   # optional\nexclude_tables: ['meta_table_*']                      # optional\n\ntarget_databases:                                     # optional\n  source_db_in_mysql_1: destination_db_in_clickhouse_1\n  source_db_in_mysql_2: destination_db_in_clickhouse_2\n  ...\n\ntarget_tables:                                        # optional\n  source_db_in_mysql_1.source_table_in_mysql_1: destination_table_name_1\n  source_db_in_mysql_1.source_table_in_mysql_2: destination_table_name_2\n  ...\n\nlog_level: 'info'               # optional       \noptimize_interval: 86400        # optional\nenable_optimize_final: True     # optional \nauto_restart_interval: 3600     # optional\n\nindexes:                        # optional\n  - databases: '*'\n    tables: ['test_table']\n    index: 'INDEX name_idx name TYPE ngrambf_v1(5, 65536, 4, 0) GRANULARITY 1'\n\npartition_bys:                  # optional\n  - databases: '*'\n    tables: ['test_table']\n    partition_by: 'toYYYYMM(created_at)'\n\nhttp_host: '0.0.0.0'    # optional\nhttp_port: 9128         # optional\n\ntypes_mapping:          # optional\n  'char(36)': 'UUID'\n\nignore_deletes: false    # optional, set to true to ignore DELETE operations\n\nmysql_timezone: 'UTC'    # optional, timezone for MySQL timestamp conversion (default: 'UTC')\n\n```\n\n#### Required settings\n\n- `mysql` MySQL connection settings\n- `clickhouse` ClickHouse connection settings\n- `binlog_replicator.data_dir` Create a new empty directory, it will be used by script to store it's state\n- `databases` Databases name pattern to replicate, e.g. `db_*` will match `db_1` `db_2` `db_test`, list is also supported\n\n#### Optional settings\n- `initial_replication_threads` - number of threads for initial replication, by default 1, set it to number of cores to accelerate initial data copy\n- `tables` - tables to filter, list is also supported\n- `exclude_databases` - databases to __exclude__, string or list, eg `'table1*'` or `['table2', 'table3*']`. If same database matches `databases` and `exclude_databases`, exclude has higher priority.\n- `exclude_tables` - databases to __exclude__, string or list. If same table matches `tables` and `exclude_tables`, exclude has higher priority.\n- `target_databases` - if you want database in ClickHouse to have different name from MySQL database\n- `target_tables` - if you want table in ClickHouse to have different name from MySQL table. Specify as `source_database.source_table: target_table_name`. The target database is determined by existing rules (e.g., `target_databases` mapping). This mapping applies to both initial and realtime replication, including DDL operations like ALTER, DROP, etc.\n- `log_level` - log level, default is `info`, you can set to `debug` to get maximum information (allowed values are `debug`, `info`, `warning`, `error`, `critical`)\n- `optimize_interval` - interval (seconds) between automatic `OPTIMIZE table` calls. Default 86400 (1 day). This is required to perform all merges guaranteed and avoid increasing of used storage and decreasing performance.\n- `enable_optimize_final` - (enabled by default) It forces ClickHouse to merge all active parts into a single part, even if large merges have already occurred. Although clickhouse documentation does NOT recommend this but we have observed [performance degradation](https://github.com/bakwc/mysql_ch_replicator/pull/223#discussion_r2659007677) and hence decided to enable it by default. Read more: https://clickhouse.com/docs/optimize/avoidoptimizefinal. You can turn it off.\n- `auto_restart_interval` - interval (seconds) between automatic db_replicator restart. Default 3600 (1 hour). This is done to reduce memory usage.\n- `binlog_retention_period` - how long to keep binlog files in seconds. Default 43200 (12 hours). This setting controls how long the local binlog files are retained before being automatically cleaned up.\n- `indexes` - you may want to add some indexes to accelerate performance, eg. ngram index for full-test search, etc. To apply indexes you need to start replication from scratch.\n- `partition_bys` - custom PARTITION BY expressions for tables. By default uses `intDiv(id, 4294967)` for integer primary keys. Useful for time-based partitioning like `toYYYYMM(created_at)`.\n- `http_host`, `http_port` - http endpoint to control replication, use `/docs` for abailable commands\n- `types_mappings` - custom types mapping, eg. you can map char(36) to UUID instead of String, etc.\n- `ignore_deletes` - when set to `true`, DELETE operations in MySQL will be ignored during replication. This creates an append-only model where data is only added, never removed. In this mode, the replicator doesn't create a temporary database and instead replicates directly to the target database.\n- `mysql_timezone` - timezone to use for MySQL timestamp conversion to ClickHouse DateTime64. Default is `'UTC'`. Accepts any valid timezone name (e.g., `'America/New_York'`, `'Europe/London'`, `'Asia/Tokyo'`). This setting ensures proper timezone handling when converting MySQL timestamp fields to ClickHouse DateTime64 with timezone information.\n- `post_initial_replication_commands` - SQL commands to execute in ClickHouse after initial replication completes for each database. Useful for creating materialized views, summary tables, or other database objects. Commands are executed in order, once per database matching the pattern.\n\n```yaml\npost_initial_replication_commands:\n  - databases: '*'\n    commands:\n      - 'CREATE TABLE IF NOT EXISTS summary_table (...) ENGINE = SummingMergeTree() ORDER BY (...)'\n      - 'CREATE MATERIALIZED VIEW IF NOT EXISTS data_mv TO summary_table AS SELECT ...'\n      - 'INSERT INTO summary_table SELECT ... FROM replicated_table'\n```\n\nFew more tables / dbs examples:\n\n```yaml\ndatabases: ['my_database_1', 'my_database_2']\ntables: ['table_1', 'table_2*']\n```\n\n**Environment Variables**: MySQL and ClickHouse credentials can be overridden using environment variables for better security in containerized environments:\n- MySQL: `MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_CHARSET`\n- ClickHouse: `CLICKHOUSE_HOST`, `CLICKHOUSE_PORT`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`\n\n### Advanced Features\n\n#### Cluster Mode\n\n`mysql_ch_replicator` supports copying data from a mysql database to a clickhouse cluster out of the box.\n\n\u003e [!IMPORTANT]\n\u003e Do not forget to define cluster.xml and macros.xml in clickhouse-server config otherwise mysql_ch_replicator will fail.\n\nPlease note:\n  1. You need to define your clickhouse cluster in /etc/clickhouse-server as explained [here](https://clickhouse.com/docs/architecture/cluster-deployment#server-setup).\n  2. To tell `mysql_ch_replicator` to run itself in cluster mode just add `cluster` name under `clickhouse` section in `config.yaml` and it will create both Distributed \u0026 Replicated Tables automatically on defined cluster and will start syncing data.\n  3. You also need to grant these permissions to clickhouse user:\n     ```\n     GRANT CLUSTER ON *.* to '\u003cuser\u003e' ON CLUSTER '\u003ccluster_name\u003e';\n\n     GRANT REMOTE ON *.* to '\u003cuser\u003e' ON CLUSTER '\u003ccluser_name\u003e';\n     ```\n  4. If you previously were using `mysql_ch_replicator` to copy data form mysql to a standalone clickhouse database but now want to convert that clickhouse standalone db to a clustered one:\n\n      a. You can do so but you will have to manually create Replicated \u0026 Distributed tables in new database.\n\n      b. Define cluster in config and `mysql_ch_replicator` will start copying data from where it left.\n\n\u003e [!WARNING]\n\u003e Converting exisitng standalone clickhouse database to clustered one and telling `mysql_ch_replicator` to resume copying to that new database will work but we do NOT recommend this because this will result in some duplicate rows. It is better to start afresh.\n\n#### Migrations \u0026 Schema Changes\n\n`mysql_ch_replicator` supports the following:\n\n- **Adding Tables**: Automatically starts replicating data from newly added tables.\n- **Altering Tables**: Adjusts replication strategy based on schema changes.\n- **Removing Tables**: Handles removal of tables without disrupting the replication process.\n\n**WARNING**. While 95% of operations supported, there could be still some unhandled operations. We try to support all of them, but for your safety, please write the CI/CD test that will check your migrations. Test should work a following way:\n - Aplly all your mysql migrations\n - Try to insert some record into mysql (to any table)\n - Check that this record appears in ClickHouse\n\n#### Known Limitations\n1. Migrations not supported during initial replication. You should either wait for initial replication finish and then apply migrations, or restart initial replication from scratch (by removing state file).\n2. Primary key changes not supported. This is a ClickHouse level limitation, it does not allow to make any changes realted to primary key.\n3. Tables without a primary key are not supported.\n\n#### Recovery Without Downtime\n\nIn case of a failure or during the initial replication, `mysql_ch_replicator` will preserve old data and continue syncing new data seamlessly. You could remove the state and restart replication from scratch.\n\n## Production usage\n\nHere is the checklist for production. Please read it carefully and confirm every point. If you have any questions - feel free to ask in discussion / issues. Following the checklist is critical to avoid any issues on prod.\n\n#### Checklist\n\n- [ ] No manual changes are made directly to ClickHouse databases or tables. All modifications (indexes, table settings, etc.) must be applied as overrides in the `mysql_ch_replicator` `config.yaml`.\n- [ ] All MySQL migrations undergo either CI/CD or manual testing before deployment. No migration is applied to production without being tested. The tests verify that replication continues to work correctly and that new records are successfully replicated from MySQL to ClickHouse after the migration.\n- [ ] Read and acknowledged [known limitations](#known-limitations).\n\n## Development\n\nTo contribute to `mysql_ch_replicator`, clone the repository and install the required dependencies:\n\n```bash\ngit clone https://github.com/your-repo/mysql_ch_replicator.git\ncd mysql_ch_replicator\npip install -r requirements.txt\n```\n\n### Running Tests\n\n1. Use docker-compose to install all requirements:\n```bash\ncd tests/\ndocker compose -f docker-compose-tests.yaml up\n```\n2. Run tests with:\n```bash\ndocker exec -w /app/ -it tests-replicator-1 python3 -m pytest -v -s tests/\n```\n3. To run a single test:\n```bash\ndocker exec -w /app/ -it tests-replicator-1 python3 -m pytest -v -s tests/ -k test_your_test_name\n```\n\n## Contribution\n\nContributions are welcome! Please open an issue or submit a pull request for any bugs or features you would like to add.\n\n## License\n\n`mysql_ch_replicator` is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.\n\n## Acknowledgements\n\nThank you to all the contributors who have helped build and improve this tool.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbakwc%2Fmysql_ch_replicator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbakwc%2Fmysql_ch_replicator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbakwc%2Fmysql_ch_replicator/lists"}