- All source data is migrated to the target at once.
- This approach utilizes continuous replication.
- Failback replication is supported, though this example will not use it. See Phased Delta Migration with Failback Replication for an example of a migration that uses failback replication.
Example scenario
You have a small (300 GB) database that provides the data store for a web application. You want to migrate the entirety of this database to a new CockroachDB cluster. Business cannot accommodate a full maintenance window, but it can accommodate a brief (<60 second) halt in traffic. The application runs on a Kubernetes cluster. Estimated system downtime: 3-5 minutes.Before the migration
- Install the MOLT (Migrate Off Legacy Technology) tools.
- Review the MOLT Fetch and MOLT Replicator documentation.
- Develop a migration plan and prepare for the migration.
- Recommended: Perform a dry run of this full set of instructions in a development environment that closely resembles your production environment. This can help you get a realistic sense of the time and complexity it requires.
- Understand the prerequisites and limitations of the MOLT tools:
Limitations
MOLT Fetch limitations
- Only tables with primary key types of
INT,FLOAT, orUUIDcan be sharded with--export-concurrency. GEOMETRYandGEOGRAPHYtypes are not supported.
MOLT Replicator limitations
- Replication modes require connection to the primary instance (PostgreSQL primary, MySQL primary/master, or Oracle primary). MOLT cannot obtain replication checkpoints or transaction metadata from replicas.
- Running DDL on the source or target while replication is in progress can cause replication failures.
-
TRUNCATEoperations on the source are not captured. OnlyINSERT,UPDATE,UPSERT, andDELETEevents are replicated. - Changes to virtual columns are not replicated automatically. To migrate these columns, you must define them explicitly with transformation rules.
- MySQL replication is supported only with GTID-based configurations. Binlog-based features that do not use GTID are not supported.
MOLT Verify limitations
-
MOLT Verify compares 20,000 rows at a time by default, and row values can change between batches, potentially resulting in temporary inconsistencies in data. To configure the row batch size, use the
--row_batch_sizeflag. -
MOLT Verify checks for collation mismatches on primary key columns. This may cause validation to fail when a
STRINGis used as a primary key and the source and target databases are using different collations. - MOLT Verify might give an error in case of schema changes on either the source or target database.
- Geospatial types cannot yet be compared.
-
MOLT Verify only supports comparing one MySQL database to a whole CockroachDB schema (which is assumed to be
public).
Step 1: Prepare the source database
In this step, you will:- Create a dedicated migration user on your source database.
- Configure the source database for replication.
Create migration user on source database
Create a dedicated migration user (for example,MIGRATION_USER) on the source database. This user is responsible for reading data from source tables during the migration. You will pass this username in the source connection string.
Configure source database for replication
Connect to the primary instance (PostgreSQL primary, MySQL primary/master, or Oracle primary), not a replica. Replicas cannot provide the necessary replication checkpoints and transaction metadata required for ongoing replication.
binlog-row-metadata or binlog-row-image to full to provide complete metadata for replication.
Configure binlog retention to ensure GTIDs remain available throughout the migration:
- MySQL 8.0.1+: Set
binlog_expire_logs_seconds(default: 2592000 = 30 days) based on your migration timeline. - MySQL < 8.0: Set
expire_logs_days, or manually manage retention by settingmax_binlog_sizeand usingPURGE BINARY LOGS BEFORE NOW() - INTERVAL 1 HOUR(adjusting the interval as needed). Force binlog rotation withFLUSH BINARY LOGSif needed. - Managed services: Refer to provider-specific configuration for Amazon RDS or Google Cloud SQL.
GTID replication sends all database changes to Replicator. To limit replication to specific tables or schemas, apply a userscript when you run Replicator. Refer to the Filter multiple tables cookbook example.
Step 2: Prepare the target database
Define the target tables
Convert the source table definitions into CockroachDB-compatible equivalents. CockroachDB supports the PostgreSQL wire protocol and is largely compatible with PostgreSQL syntax.-
The source and target table definitions must match. Review Type mapping to understand which source types can be mapped to CockroachDB types.
MySQL tables belong directly to the database specified in the connection string. A MySQL source table defined as
CREATE TABLE tbl (id INT PRIMARY KEY);should map to CockroachDB’s defaultpublicschema:-
MOLT Fetch can automatically define matching CockroachDB tables using the
drop-on-target-and-recreateoption. - If you define the target tables manually, review how MOLT Fetch handles type mismatches. You can use the MOLT Schema Conversion Tool to create matching table definitions.
-
MOLT Fetch can automatically define matching CockroachDB tables using the
-
Every table must have an explicit primary key.
Avoid using sequential keys. To learn more about the performance issues that can result from their use, refer to the guidance on indexing with sequential keys. If a sequential key is necessary in your CockroachDB table, you must create it manually, after using MOLT Fetch to load and replicate the data.
- Review Transformations to understand how computed columns and partitioned tables can be mapped to the target, and how target tables can be renamed.
-
By default on CockroachDB,
INTis an alias forINT8, which creates 64-bit signed integers. PostgreSQL and MySQL default to 32-bit integers. Depending on your source database or application requirements, you may need to change the integer size to4. For more information, refer to Considerations for 64-bit signed integers.
Schema Conversion Tool
The MOLT Schema Conversion Tool (SCT) converts source table definitions to CockroachDB-compatible syntax. It requires a free CockroachDB Cloud account.-
Upload a source
.sqlfile to convert the syntax and identify unimplemented features and syntax incompatibilities in the table definitions. -
Import the converted table definitions to a CockroachDB cluster:
- When migrating to CockroachDB Cloud, the Schema Conversion Tool automatically applies the converted table definitions to a new Cloud database.
- When migrating to a self-hosted CockroachDB cluster, export a converted DDL file and pipe the data definition language (DDL) directly into
cockroach sql.
String case sensitivity
Strings are case-insensitive in MySQL and case-sensitive in CockroachDB. You may need to edit your MySQL data to get the results you expect from CockroachDB. For example, you may have been doing string comparisons in MySQL that will need to be changed to work with CockroachDB. For more information about the case sensitivity of strings in MySQL, refer to Case Sensitivity in String Searches from the MySQL documentation. For more information about CockroachDB strings, refer toSTRING.
Identifier case sensitivity
Identifiers are case-sensitive in MySQL and case-insensitive in CockroachDB. When using the Schema Conversion Tool, you can either keep case sensitivity by enclosing identifiers in double quotes, or make identifiers case-insensitive by converting them to lowercase.AUTO_INCREMENT attribute
The MySQL AUTO_INCREMENT attribute, which creates sequential column values, is not supported in CockroachDB. When using the Schema Conversion Tool, columns with AUTO_INCREMENT can be converted to use sequences, UUID values with gen_random_uuid(), or unique INT8 values using unique_rowid(). Cockroach Labs does not recommend using a sequence to define a primary key column. For more information, refer to Unique ID best practices.
Changing a column type during table definition conversion will cause MOLT Verify to identify a type mismatch during data validation. This is expected behavior.
ENUM type
MySQL ENUM types are defined in table columns. On CockroachDB, ENUM is a standalone type. When using the Schema Conversion Tool, you can either deduplicate the ENUM definitions or create a separate type for each column.
TINYINT type
TINYINT data types are not supported in CockroachDB. The Schema Conversion Tool automatically converts TINYINT columns to INT2 (SMALLINT).
Geospatial types
MySQL geometry types are not converted to CockroachDB geospatial types by the Schema Conversion Tool. They should be manually converted to the corresponding types in CockroachDB.FIELD function
The MYSQL FIELD function is not supported in CockroachDB. Instead, you can use the array_position function, which returns the index of the first occurrence of element in the array.
Example usage:
NULL. So if you are using the ORDER BY clause in a statement with the array_position function, the caveat is that sort is applied even when the element is not found. As a workaround, you can use the COALESCE operator.
Drop constraints and indexes
To optimize data load performance, drop all non-PRIMARY KEY constraints and indexes on the target CockroachDB database before migrating:
FOREIGN KEYUNIQUE- Secondary indexes
CHECKDEFAULTNOT NULL(you do not need to drop this constraint when usingdrop-on-target-and-recreatefor table handling)
Do not drop
PRIMARY KEY constraints.Create the SQL user
Create a SQL user in the CockroachDB cluster that has the necessary privileges. To create a usercrdb_user in the default database (you will pass this username in the target connection string):
migration_schema schema and internal MOLT tables like _molt_fetch_exceptions in the public CockroachDB schema:
Ensure that you are connected to the target database.
drop-on-target-and-recreate will not be used), grant the following privileges on the schema:
drop-on-target-and-recreate, and the target schema has pre-existing tables that were created by a different user, you may need to change table ownership to allow the migration user to drop those tables. Make the following alteration for each table:
IMPORT INTO or COPY FROM on the target tables:
IMPORT INTO privileges
Grant SELECT, INSERT, and DROP (required because the table is taken offline during the IMPORT INTO) privileges on all tables being migrated:
EXTERNALIOIMPLICITACCESS system-level privilege:
COPY FROM privileges
Grant admin privileges to the user:
Set session variable
Ensure that thestatement_timeout session variable is set to 0s for the user:
Replication privileges
Grant permissions to create the staging schema for replication:Configure GC TTL
Before starting the initial data load, configure the garbage collection (GC) TTL on the source CockroachDB cluster to ensure that historical data remains available when replication begins. The GC TTL must be long enough to cover the full duration of the data load. Increase the GC TTL before starting the data load. For example, to set the GC TTL to 24 hours:The GC TTL duration must be higher than your expected time for the initial data load.
Step 3: Load data into CockroachDB
In this step, you will:- Configure MOLT Fetch with the flags needed for your migration.
- Run MOLT Fetch.
- Understand how to continue a load after an interruption.
Configure MOLT Fetch
The MOLT Fetch documentation includes detailed information about how to configure MOLT Fetch, and how to monitor MOLT Fetch metrics. When you runmolt fetch, you can configure the following options for data load:
- Specify source and target databases: Specify URL‑encoded source and target connections.
- Select data to migrate: Specify schema and table names to migrate.
- Define intermediate file storage: Export data to cloud storage or a local file server.
- Define fetch mode: Specifies whether data will only be loaded into/from intermediate storage.
- Shard tables: Divide larger tables into multiple shards during data export.
- Data load mode: Choose between
IMPORT INTOandCOPY FROM. - Table handling mode: Determine how existing target tables are initialized before load.
- Define data transformations: Define any row-level transformations to apply to the data before it reaches the target.
- Monitor fetch metrics: Configure metrics collection during initial data load.
molt fetch command and its flags. Follow best practices, especially those related to security.
At minimum, the molt fetch command should include the source, target, data path, and --ignore-replication-check flags:
Run MOLT Fetch
Perform the initial load of the source data.-
Issue the MOLT Fetch command to move the source data to CockroachDB. This example command passes the source and target connection strings as environment variables, writes intermediate files to S3 storage, and uses the
truncate-if-existstable handling mode to truncate the target tables before loading data. It also limits the migration to a single schema and filters three specific tables to migrate. The data load mode defaults toIMPORT INTO. -
Check the output to observe
fetchprogress. Astarting fetchmessage indicates that the task has started:data extractionmessages are written for each table that is exported to the location in--bucket-path:data importmessages are written for each table that is loaded into CockroachDB:Afetch completemessage is written when the fetch task succeeds:This message includes acdc_cursorvalue. You must set the--defaultGTIDSetreplication flag to this value when starting Replicator:
Continue MOLT Fetch after an interruption
If MOLT Fetch fails while loading data into CockroachDB from intermediate files, it exits with an error message, fetch ID, and continuation token for each table that failed to load on the target database.- All data has been exported from the source database into intermediate files on cloud or local storage.
- The initial load of source data into the target CockroachDB database is incomplete.
- The load uses
IMPORT INTOrather thanCOPY FROM.
Only one fetch ID and set of continuation tokens, each token corresponding to a table, are active at any time. See List active continuation tokens.
Step 4: Verify the initial data load
Use MOLT Verify to confirm that the source and target data is consistent. This ensures that the data load was successful.Run MOLT Verify
-
Run the MOLT Verify command, specifying the source and target connection strings and the tables to validate.
-
Check the output to observe
verifyprogress. Averification in progressindicates that the task has started:starting verifymessages are written for each specified table:Afinished row verificationmessage is written after each table is compared. Ifnum_successequalsnum_truth_rowsand the error counters (num_missing,num_mismatch,num_extraneous, andnum_column_mismatch) are all0, the table verified successfully. Any non-zero values in the error counters indicate data discrepancies that need investigation. For details on each field, refer to the MOLT Verify page.Averification completemessage is written when the verify task succeeds:
Step 5: Finalize the target schema
Add constraints and indexes
Add any constraints or indexes that you previously removed from the CockroachDB schema to facilitate data load.If you used the
--table-handling drop-on-target-and-recreate option for data load, only PRIMARY KEY and NOT NULL constraints are preserved. You must manually recreate all other constraints and indexes.ALTER TABLE ... ADD CONSTRAINT and CREATE INDEX. Review the best practices for creating secondary indexes on CockroachDB.
Step 6: Begin forward replication
In this step, you will:- Configure MOLT Replicator with the flags needed for your migration.
- Start MOLT Replicator.
- Understand how to continue replication after an interruption.
Configure MOLT Replicator
When you runreplicator, you can configure the following options for replication:
- Replication connection strings: Specify URL-encoded source and target database connections.
- Replicator flags: Specify required and optional flags to configure replicator behavior.
- Replicator metrics: Monitor replication progress and performance.
Replication connection strings
MOLT Replicator uses--sourceConn and --targetConn to specify the source and target database connections.
--sourceConn specifies the connection string of the source database:
--targetConn specifies the target CockroachDB connection string:
Replicator flags
Configure the following MOLT Replicator flags for continuous replication. For details on all available flags, refer to Replicator Flags.
You can find the starting GTID in the
cdc_cursor field of the fetch complete message after the initial data load completes.
Replicator metrics
MOLT Replicator metrics are not enabled by default. Enable Replicator metrics by specifying the--metricsAddr flag with a port (or host:port) when you start Replicator. This exposes Replicator metrics at http://{host}:{port}/_/varz. For example, the following flag exposes metrics on port 30005:
Start MOLT Replicator
With initial load complete, start replication of ongoing changes on the source to CockroachDB using MOLT Replicator.MOLT Fetch captures a consistent point-in-time checkpoint at the start of the data load (shown as
cdc_cursor in the fetch output). Starting replication from this checkpoint ensures that all changes made during and after the data load are replicated to CockroachDB, preventing data loss or duplication. The following steps use the checkpoint values from the fetch output to start replication at the correct position.-
Run the
replicatorcommand, specifying the GTID from the checkpoint recorded during data load. Use--stagingSchemato specify a unique name for the staging database, and include--stagingCreateSchemato have MOLT Replicator automatically create the staging database. If you filtered tables during the initial load, write a userscript to filter tables on replication and specify the path with--userscript.
Check that replication is working
-
Verify that Replicator is processing changes successfully. To do so, check the MOLT Replicator logs. Since you enabled debug logging with
-v, you should see connection and row processing messages: You should see binlog syncer connection and row processing:When rows are successfully replicated, you should see debug output like the following:These messages confirm successful replication. You can disable verbose logging after verifying the connection.
Continue MOLT Replicator after an interruption
Run the MOLT Replicatormylogical command using the same --stagingSchema value from your initial replication command.
Replicator will automatically use the saved GTID (Global Transaction Identifier) from the memo table in the staging schema (in this example, defaultdb._replicator.memo) and track advancing GTID checkpoints there. To have Replicator start from a different GTID instead of resuming from the checkpoint, clear the memo table with DELETE FROM defaultdb._replicator.memo; and run the replicator command with a new --defaultGTIDSet value.
http://localhost:30005/_/varz to track replication progress.
Step 7: Stop application traffic
Once the inital data load has been verified and the target schema has been finalized, it’s time to begin the cutover process. First, stop application traffic to the source. Scale down the Kubernetes cluster to zero pods.Application downtime begins now.It is strongly recommended that you perform a dry run of this migration in a test environment. This will allow you to practice using the MOLT tools in real time, and it will give you an accurate sense of how long application downtime might last.
Step 8: Stop forward replication
Before you can cut over traffic to the target, the changes to the source database need to finish being written to the target. Once the source is no longer receiving write traffic, MOLT Replicator will take some seconds to finish replicating the final changes. This is known as drainage.-
Wait for replication to drain, which means that all transactions that occurred on the source database have been fully processed and replicated. There are several ways to determine that replication has fully drained:
-
When replication is caught up, you will not see new
upserted rowslogs. -
If you set up the replication metrics endpoint with
--metricsAddrin the preceding steps, metrics are available at:Use the following Prometheus alert expression to observe when the combined rate of upserts and deletes is0for each schema: -
You can also check Prometheus metrics associated with replication lag, including
target_apply_transaction_lag_seconds,core_source_lag_seconds, andsource_commit_to_apply_lag_seconds.
-
When replication is caught up, you will not see new
-
Cancel replication by entering
ctrl-cto issue aSIGTERMsignal. This returns an exit code0.

