Note:
- This tutorial requires access to Oracle Cloud. To sign up for a free account, see Get started with Oracle Cloud Infrastructure Free Tier.
- It uses example values for Oracle Cloud Infrastructure credentials, tenancy, and compartments. When completing your lab, substitute these values with ones specific to your cloud environment.
Migrate On-Premises MySQL Database to Oracle HeatWave MySQL Managed Instance using OCI GoldenGate
Introduction
Oracle Cloud Infrastructure GoldenGate (OCI GoldenGate) is a fully managed service that helps data engineers move data in real-time, at scale, from one or more data management systems to OCI databases. Design, run, orchestrate, and monitor data replication tasks in a single interface without having to allocate or manage any compute environments. OCI GoldenGate supports several sources and targets, including MySQL and Oracle HeatWave MySQL database service.
In this tutorial, we will guide you how to migrate on-premises MySQL database to Oracle HeatWave MySQL managed instance using OCI GoldenGate.
Objectives
- Migrate on-premises MySQL database to Oracle HeatWave MySQL managed instance on OCI using OCI GoldenGate.
Prerequisites
-
Source MySQL database is on-premises and target Oracle Heatwave MySQL managed instance and OCI Bastion host are in place.
-
Since this is unidirectional replication the target can be on a higher version than source. In case of bidirectional replication it is recommended that source and target be on the same version.
-
log_bin
(binlog) must be enabled on the source. -
The
binlog_expire_logs_second
instance parameter on source and target instances must be set to atleast 72 hours. -
The
binlog_row_metadata
instance parameter on source and target instances must be set to full to allow Data Definition Language (DDL) replication.Note: In this tutorial, the source is running MySQL version
5.7.44
wherebinlog_row_metadata
parameter is not supported. Hence, DDL replication is not supported. -
Global transaction identifier (GTID) mode must be on the source if target Oracle Heatwave MySQL instance has high availability (HA), otherwise it is optional.
-
Review supported data types. For more information, see MySQL: Supported Data Types, Objects, and Operations.
-
Review DDL replication limitations. For more information, see Using DDL Replication.
-
Target instance should be created ahead of time from source using one of these methods:
- Method 1: Using MySQL shell utilities like
util.dumpInstance
andutil.loadDump
. - Method 2: Using MySQL shell utilities like
util.copyInstance
. - Method 3: Using OCI GoldenGate for initial Extract and Replicat to perform the initial data load.
Note: In this tutorial, we will be using
util.copyInstance
for initial load. - Method 1: Using MySQL shell utilities like
-
OCI Bastion host with MySQL client and MySQL Shell utility installed in OCI.
-
FastConnect/IPSec/VPN, ingress rules and updated security lists to allow communication between on-premises source, target Oracle Heatwave MySQL, bastion and OCI GoldenGate.
Limitations
-
Auto increment column issues.
-
If a table has one column and that is not primary key or unique key then mapping fails because the combination of all columns for that table is same on source and target.
-
Data types, DDL and other feature limitations.
-
When using Active-Active replication, the time zones must be the same on both systems so that timestamp-based conflict resolution and detection can operate.
Task 1: Create Source and Target MySQL Instances
-
Source:
-On-premise Hostname: MySQLCI57 OEL 7.9 MySQL version 5.7.44 Intel Hardware Standard.Flex3 with 4 CPUs and 32GB Dedicated VM
-
Target:
-OCI Oracle Heatwave MySQL Managed Instance Hostname: MySQLGG1 with HA and no heatwave (4CPU and 32GB) OEL 8 with latest build MySQL version: 8.4.4 Private subnet
-
OCI Bastion host:
-OCI Hostname: Bastion OEL 8 with Intel hardware Standard.Flex3 with 4CPUs and 32GB
Task 2: Test Connections between Bastion, On-Premises and Oracle Heatwave MySQL Instances
-
Install MySQL client and MySQL Shell utility on the OCI Bastion host.
-
Test connection from OCI Bastion to source on-premises MySQL instance.
[root@bastion ~]# mysql --host <sourceIP> -uadmin -p mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 15 Server version: 5.7.44 MySQL Community Server (GPL) Copyright (c) 2000, 2025, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec) mysql> select @@version; +-----------+ | @@version | +-----------+ | 5.7.44 | +-----------+ 1 row in set (0.00 sec)
-
Test connection from source on-premises MySQL to the Oracle Heatwave MySQL managed instance.
[root@mysqlci57 ~]# mysql --host <targetIP> -u admin -p mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 108 Server version: 8.4.4-u5-cloud MySQL Enterprise - Cloud Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> select @@version; +----------------+ | @@version | +----------------+ | 8.4.4-u5-cloud | +----------------+ 1 row in set (0.01 sec)
Task 3: Create Users for OCI GoldenGate
-
Source:
create user 'ggsuser_S'@'%' identified by "<password>"; grant all privileges on airportdb.* to 'ggsuser_S'@'%' with grant option; Grant select, process, replication slave, reload, replication client on *.* to 'ggsuser_S'@'%';
-
Target:
create user 'ggsuser_T'@'%' identified by "<password>"; grant all privileges on airportdb.* to 'ggsuser_T'@'%' with grant option; Grant select, process, replication slave, replication client on *.* to 'ggsuser_T'@'%'; Create database ggadmin; -- you create this db on target side to store the checkpoint table. grant all privileges on ggadmin.* to 'ggsuser_T'@'%' with grant option;
Task 4: Set Mandatory Parameters in the Source Database for OCI GoldenGate
It is not mandatory to turn on GTID on source if the target is standalone (not HA). But if target is HA then it is highly recommended to turn on GTID on source.
It is mandatory to turn on the binlog
mode.
-
Edit the
/etc/my.cnf
file and add the following lines.server-id=1 log-bin=/var/log/mysql/mysql-bin.log max_binlog_size=100M binlog_format=ROW expire_logs_days=10 -- binlog_row_metadata=FULL <-- this is not supported in Version 5.7.44. So DDL replication will not be possible if source is on v5.7.44. gtid_mode=ON enforce_gtid_consistency=ON
-
Restart MySQL server.
Systemctl stop mysqld Systemctl start mysqld Systemctl status mysqld
For complete list or parameters, check transaction log settings and requirements. For more information, see Option B: Use your own bastion on OCI Compute.
-
Run the following command to check that binary logs is enabled now.
mysql> show binary logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000001 | 154 | +------------------+-----------+ 1 row in set (0.00 sec) mysql> show variables like 'bin%'; +--------------------------------------------+--------------+ | Variable_name | Value | +--------------------------------------------+--------------+ | bind_address | * | | binlog_cache_size | 32768 | | binlog_checksum | CRC32 | | binlog_direct_non_transactional_updates | OFF | | binlog_error_action | ABORT_SERVER | | binlog_format | ROW | | binlog_group_commit_sync_delay | 0 | | binlog_group_commit_sync_no_delay_count | 0 | | binlog_gtid_simple_recovery | ON | | binlog_max_flush_queue_time | 0 | | binlog_order_commits | ON | | binlog_row_image | FULL | | binlog_rows_query_log_events | OFF | | binlog_stmt_cache_size | 32768 | | binlog_transaction_dependency_history_size | 25000 | | binlog_transaction_dependency_tracking | COMMIT_ORDER | +--------------------------------------------+--------------+ 16 rows in set (0.01 sec)
-
Run the following command to check that GTID mode (
gtid_mode
) is on.mysql> show variables like 'gtid%'; +----------------------------------+-----------+ | Variable_name | Value | +----------------------------------+-----------+ | gtid_executed_compression_period | 1000 | | gtid_mode | ON | <--- it is now showing ON | gtid_next | AUTOMATIC | | gtid_owned | | | gtid_purged | | +----------------------------------+-----------+ 5 rows in set (0.00 sec) mysql> select @@gtid_executed, @@gtid_purged\G *************************** 1. row *************************** @@gtid_executed: @@gtid_purged: 1 row in set, 1 warning (0.00 sec) mysql> select * from mysql.gtid_executed; Empty set (0.00 sec) <--- this is empty because we just turned it ON. As transactions occur this will get populated
Note: It is common for the first query to show NULL values for GTID. This is because in MySQL
versions 5.7
the GTID value is stored only in themysql.gtid_executed
table.
Task 5: Create the airportdb
Schema (Metadata only) in the Target Database
-
Extract the schema metadata from the source database.
[root@bastion airport-db]# mysqldump --host <SourceIP> -u admin -p --no-data --routines --events airportdb > airportdb.sql mysqldump: [Warning] Using a password on the command line interface can be insecure. -- Warning: column statistics not supported by the server.
-
Import the schema metadata into the target database.
[root@bastion opc]# mysql --host <TargetIP> -u admin -p mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 581 Server version: 8.4.4-u5-cloud MySQL Enterprise - Cloud Copyright (c) 2000, 2025, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database airportdb; Query OK, 1 row affected (0.01 sec) mysql> use airportdb; Database changed mysql> source airportdb.sql
Task 6: Set up OCI GoldenGate Deployment and Add Connections
There are several blogs, tutorials on how to set up OCI GoldenGate deployments, so here we are going to show a few steps.
-
Log in to the OCI Console and select GoldenGate Deployments.
-
Click Create deployment and enter the required information as shown in the following image.
-
Add source and target connection details on the Create deployment page.
-
Assign the connections to the OCI GoldenGate deployment. Click the connection name and then Assign deployment.
-
Using OCI Bastion service, set up port forwarding to port
443
and then log in to the OCI GoldenGate console. -
Validate the database connections from the OCI GoldenGate console.
-
Click the Hamburger menu and you will see the two connections added to the deployment in Task 6.4.
-
Click Connect to validate the connections. If connections are successful you will see the option to create checkpoint table by clicking Checkpoint +.
It is highly recommended to add the connections using OCI GoldenGate deployment in OCI as it will automatically append the DNS to the IP addresses, without these DNS the test connections will fail.
-
Task 7: Create Extract and Replicat Processes
-
Before you create the Extract process make sure that
gtid_mode
is ON in the source database, especially if the target is HA.There are two methods to add Extract:
-
Method 1: You can add Extract after initial load (copy or dump instance) is complete and use precise instantiation method. For more information, see Precise Instantiation for MySQL to MySQL Using MySQL Shell Utilities and Oracle GoldenGate.
To add Extract and start it to do data capture from that particular GTID or binlog as shown in the following image. Oracle recommends to use this method.
Note: Here the GTID set is taken from the JSON file of the
dumpInstance
or output of thecopyInstance
commands. -
Method 2: You can add Extract at the very beginning before you even start initial data load and then later alter Replicat to start with a particular
gtidexecuted/binlog#
and binlog position that is displayed in the JSON file of thedumpInstance()
or output ofcopyInstance()
.Use
HANDLECOLLISION
parameter with this method to avoid any duplicate data issue.Note: For this POC, Method 2 was used.
Edit the extract parameter file:
EXTRACT ext1 USERIDALIAS MySQLCI57, DOMAIN OracleGoldenGate EXTTRAIL e1 --DDL INCLUDE MAPPED (needed for DDL replication, also need to set binlog_row_metadata to FULL in mysql config file on source db). But not supported for MySQL V5.7 TRANLOGOPTIONS FETCHPARTIALJSON (for JSON replication, also need to set binlog_row_value_options to empty string in the mysql config) TABLE airportdb.*;
Note: If you add
DDL INCLUDE MAPPED
to Extract parameter file then you will get error that DDL replication is not supported for MySQLversion 5.7.4
.
-
-
Start the Extract process.
-
Extract is running and generating the trail file, now create Replicat.
-
Create checkpoint table first. Go to the Configuration section, select the target database and click Checkpoint + to create checkpoint table.
-
Create Replicat process. Since this is unidirectional replication we can go with parallel Replicat for better performance. For bidirectional replication only classic Replicat is supported.
Do not start the Replicat process, just create it. We will start it after the data is imported.
-
Edit the parameter file. You may also add
PARALLEL
parameters or the default parallelism will be used.REPLICAT rep1 USERIDALIAS MySQLGG1, DOMAIN OracleGoldenGate MAP airportdb.*, TARGET airportdb.*;
-
Task 8: Copy Data from Source to Target using the copyInstance()
-
Perform a dry run using
dryRun:"true"
option ofcopyInstance()
.Type '\help' or '\?' for help; '\quit' to exit. MySQL SQL > \connect admin@<Source IP> Creating a session to 'admin@<Source IP>' Fetching global names for auto-completion... Press ^C to stop. Your MySQL connection id is 37 Server version: 5.7.44-log MySQL Community Server (GPL) No default schema selected; type \use <schema> to set one. MySQL <Source IP>:3306 ssl SQL > \js Switching to JavaScript mode... MySQL <Source IP>:3306 ssl JS > util.copyInstance('mysql://admin@<Target IP>', {"compatibility":["skip_invalid_accounts","strip_definers","strip_restricted_grants","strip_tablespaces","ignore_wildcard_grants","strip_invalid_grants","create_invisible_pks"], users:"true", threads:2, dryRun:"true"}); Please provide the password for 'admin@<target IP': ******************* Save password for 'admin@<target IP>'? [Y]es/[N]o/Ne[v]er (default No):
-
If there are no errors, then remove the
dryRun
option and re-run to perform the data load. The final output should look like this: No errors reported.SRC: Starting data dump 100% (59.50M rows / ~59.36M rows), 142.25K rows/s, 9.68 MB/s SRC: Dump duration: 00:07:50s SRC: Total duration: 00:07:50s SRC: Schemas dumped: 2 SRC: Tables dumped: 15 SRC: Data size: 2.03 GB SRC: Rows written: 59502422 SRC: Bytes written: 2.03 GB SRC: Average throughput: 4.33 MB/s 1 thds indexing \ 100% (2.03 GB / 2.03 GB), 7.47 MB/s (161.06K rows/s), 15 / 15 tables done Building indexes - done Executing common postamble SQL - done TGT: 53 chunks (59.50M rows, 2.03 GB) for 15 tables in 2 schemas were loaded in 7 min 51 sec (avg throughput 4.32 MB/s, 126.29K rows/s) TGT: 17 DDL files were executed in 0 sec. TGT: 0 accounts were loaded, 3 accounts failed to load due to unsupported authentication plugin errors TGT: Data load duration: 7 min 51 sec TGT: 1 indexes were built in 0 sec. TGT: Total duration: 7 min 51 sec TGT: 0 warnings were reported during the load. .. .. Dump_metadata: Binlog_file: mysql-bin.000006 Binlog_position: 626 Executed_GTID_set: 7ee61c32-16eb-11f0-b3fc-02001702dcb5:1-3
Note: Make a note of the GTID executed shown in the output of
copyInstance()
and use this to alter the Replicat.
Task 9: Alter Replicat and Start
Use the logfile number which is 000006
and log position number which is 626
as shown in the output of the copyInstance()
in Task 8. This logfile and log position should be used in the format to generate CSN 000006:000000000000626
.
Alter Replicat and click Start to start.
Replicat status showing as Running.
Note: If you had used Method 1 for adding Extract as shown in Task 7, the altering Replicat will not be needed. In this POC, we used Method 2 to add Extract. Either methods work fine.
Task 10: Run DML Tests
Test the replication by performing DML activity on source.
-
Source:
mysql> select count(*) from passenger; +----------+ | count(*) | +----------+ | 36095 | +----------+ 1 row in set (0.01 sec) mysql> insert into passenger (passportno,firstname,lastname) values ('Pd89UKL','Timothy','London'); Query OK, 1 row affected (0.00 sec) mysql> commit -> ; Query OK, 0 rows affected (0.00 sec) mysql> select count(*) from passenger; +----------+ | count(*) | +----------+ | 36096 | +----------+ 1 row in set (0.00 sec) mysql> select @@version; +------------+ | @@version | +------------+ | 5.7.44-log | +------------+ 1 row in set (0.00 sec)
-
Target:
[root@bastion opc]# mysql --host <target IP> -u admin -p mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1249 Server version: 8.4.4-u5-cloud MySQL Enterprise - Cloud Copyright (c) 2000, 2025, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use airportdb; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select count(*) from passenger; +----------+ | count(*) | +----------+ | 36096 | +----------+ 1 row in set (0.00 sec) mysql> select @@version -> ; +----------------+ | @@version | +----------------+ | 8.4.4-u5-cloud | +----------------+ 1 row in set (0.00 sec)
Related Links
-
Connect to Oracle Cloud Infrastructure GoldenGate using a private IP
-
MySQL: Prerequisites for Transaction Log Based DDL Configuration
-
Loading Data from File to Replicat in Microservices Architecture
-
MySQL: Supported Data Types, Objects, and Operations for OCI GoldenGate
Acknowledgments
- Author - Chakradhar Jagganagari (Lift Implementation Expert - Database)
More Learning Resources
Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.
For product documentation, visit Oracle Help Center.
Migrate On-Premises MySQL Database to Oracle HeatWave MySQL Managed Instance using OCI GoldenGate
G34793-01
Copyright ©2025, Oracle and/or its affiliates.