Skip to content
Adapters

Oracle to MySQL migration tools and converters compared on what actually lands

Ten ways to move an Oracle database into MySQL, judged on the rows that arrive. AWS's own examples turn Oracle NUMBER into a floating-point DOUBLE, and MySQL's own migration wizard does not list Oracle as a supported source. Both facts are in the vendors' own documentation, and both change what a sensible migration plan looks like.

The live demo needs no card, and Starter is $49 a month.

Field mapping auto-plugged · tap a port to rewire

5 sample records ready

Vendor documentation read 1 October 2026

Which Oracle to MySQL migration tool should you use?

For a one-time move into RDS or Aurora MySQL, use AWS SCT for the schema and DMS for the data. For PL/SQL heavy schemas, use a code converter such as SQLines or Ispirer. For an ongoing sync while the application is rewritten, use a tool that lets you declare the MySQL columns. Do not plan on MySQL Workbench converting Oracle for you, and correct four type decisions by hand before any data moves.

Four Oracle values and what a careless mapping turns them into in MySQL, with DATE losing its time, NUMBER becoming approximate, a zoned timestamp losing its zone, and the correct DATETIME target. ORACLE MYSQL, CARELESS MAP DATE NUMBER TIMESTAMP WITH TZ DATE, again DATE time of day dropped DOUBLE approximate, not exact DATETIME zone dropped DATETIME what to declare instead
Three mappings that load without an error, and the correction for the most common one.

This route sits under our data migration tools guide. If PostgreSQL is still on the table as the target, the same Oracle source with very different type and code rules is compared on Oracle to PostgreSQL migration tools.

Eight documented behaviors that change your data between Oracle and MySQL

Each row sets a tool's documentation, or a default, against what Oracle or MySQL say about the same type or setting. The first two are the ones nobody checks, because they come from the two names people trust most on this route: MySQL's own tool and AWS's own converter.

Tool and setting What the documentation says Why it matters to a buyer What we would ship
MySQL Workbench, Oracle source The Workbench manual lists seven supported sources: SQL Server, Access, MySQL, PostgreSQL, SQL Anywhere, SQLite and Sybase ASE. Oracle is not one. Other products go through generic ODBC, which the manual calls "less automatic". Several page-one guides tell you to select Oracle in the wizard. Teams plan a free, automatic conversion and find themselves writing the type mapping by hand. Budget it as manual work
AWS SCT, NUMBER in code AWS's own Oracle to MySQL examples convert a parameter declared "p_state IN NUMBER" to "par_P_STATE DOUBLE" and a NUMBER variable to DOUBLE. MySQL says floating-point values "are approximate and not stored as exact values." Money arithmetic inside converted procedures moves from exact decimal to binary floating point. Comparisons for equality start failing on values that look identical. DECIMAL(p,s) in every signature
SQLines, bare NUMBER The published mapping sends an unconstrained NUMBER to "DECIMAL(p,s) or DOUBLE". Oracle says a NUMBER with no precision or scale "specifies the maximum range and precision for an Oracle number." Bare NUMBER is how many Oracle schemas declare every money and quantity column. Whichever target is chosen, it is a guess until someone measures the data. Profile, then DECIMAL
Name-matched DDL, DATE Oracle: "For each DATE value, Oracle stores the following information: year, month, day, hour, minute, and second." MySQL DATE stores the calendar date only. Converters map DATE to DATETIME correctly. Hand-edited and find-and-replace DDL keeps the name and drops every time of day, with no error and no warning. DATETIME, never DATE
SQLines, TIMESTAMP WITH TIME ZONE Mapped to DATETIME(p) "with time zone handling". Oracle stores a zone region or offset inside each value. No MySQL type keeps it. Events written from New York and Los Angeles at the same instant land three hours apart. Every row is present and every value is plausible. UTC value plus a zone column
AWS SCT, RDS or Aurora target AWS asks for lower_case_table_names set to 1. MySQL 8.4 says it "can only be configured when initializing the server" and that the Unix default is 0. Oracle stores unquoted names in upper case. Teams create the instance first, find ORDERS and orders are different tables, and learn the fix is a new instance. Parameter group before create
Oracle, empty strings Oracle "treats a character value with a length of zero as null." MySQL stores '' as a real value, distinct from NULL. Nothing breaks at load. After cutover the application writes blanks into columns that were NOT NULL to keep blanks out, and IS NULL reports undercount. CHECK (col <> '') per column
MySQL 8.4, default collation Server default is utf8mb4 with utf8mb4_0900_ai_ci, accent and case insensitive. A default Oracle database compares strings in binary, so case and accents count. SMITH and Smith were two customer codes in Oracle and are one value in MySQL. The unique index fails to build, or a loader with INSERT IGNORE drops the second row. utf8mb4_bin on unique keys

The second row is the one to take away. Oracle NUMBER is an exact decimal type, and most Oracle code declares money as a plain NUMBER because Oracle never made anyone choose. AWS's published conversion examples turn those declarations into MySQL DOUBLE, a binary floating-point type MySQL itself warns is approximate. The table data can be perfect while every procedure that adds it up is not. If the plan is to keep MySQL current from Oracle rather than move once, the capture options are compared in change data capture tools.

Oracle types in MySQL, and the wrong target a careless map picks

An Oracle to MySQL converter is mostly a type converter, and Oracle makes it harder than most sources because one type, NUMBER, covers integers, decimals and floating point alike. BINARY_FLOAT, BINARY_DOUBLE, BLOB and RAW cross cleanly. These twelve are the ones where the obvious choice is wrong.

Oracle type Right MySQL target Common wrong target
NUMBER (no precision) DECIMAL sized from the data DOUBLE, which is approximate
NUMBER(p,s) DECIMAL(p,s) DOUBLE or FLOAT in converted code
NUMBER(10) BIGINT INT, which stops at 2,147,483,647
NUMBER(19) to NUMBER(38) DECIMAL(p,0) BIGINT, which stops at 19 digits
NUMBER(p,-s) DECIMAL(p,0) Nothing. MySQL has no negative scale
DATE DATETIME DATE, which drops the time of day
TIMESTAMP(9) DATETIME(6) TIMESTAMP, which ends in 2038
TIMESTAMP WITH TIME ZONE DATETIME(6) in UTC plus a zone column DATETIME with the zone dropped
VARCHAR2(n BYTE) VARCHAR(n) after a row-width check Wide VARCHARs that break 65,535 bytes
CHAR(n) CHAR(n), or VARCHAR(n) if padding matters CHAR read back without trailing spaces
CLOB, NCLOB, XMLTYPE LONGTEXT TEXT, which caps at 64 KB
ROWID, sequences Drop ROWID, AUTO_INCREMENT A stored ROWID that means nothing

Two limits catch teams on shape rather than values. Oracle VARCHAR2 lengths default to bytes, so a VARCHAR2(4000) holds 4,000 bytes. MySQL VARCHAR lengths are characters, and utf8mb4 budgets up to four bytes each, so the same declaration claims 16,000 bytes of a row that is capped at 65,535. A table with five of them fails with error 1118. Names are the second: Oracle stores unquoted identifiers in upper case, and MySQL on Linux treats table names as case sensitive unless the server was initialized otherwise. The full per-type walkthrough, with a query to run on Oracle for each risky mapping, is in our guide to converting Oracle DDL to MySQL.

Oracle to MySQL migration tools and converters compared

Billing units rather than price tags, except where the vendor publishes the number itself, as with Fivetran's $5 base charge per connection. Everything else is quoted, metered in ways that depend on your data, or has no license fee. Where a tool is wrong for a job, the last column says so, including for us.

Tool Approach Best for Billing unit What to watch
AWS SCT Schema and PL/SQL conversion with an assessment report Planning a move to RDS or Aurora MySQL No charge for the tool itself NUMBER to DOUBLE in converted code
AWS DMS Full load plus ongoing replication from Oracle One-time moves inside AWS with a cutover date Replication instance hours or serverless capacity Moves data, not PL/SQL
MySQL Workbench Generic ODBC migration, not a listed Oracle source Small schemas and a DBA with time Community edition under the GPL Manual type mapping
SQLines Converts DDL, queries and PL/SQL, plus a data tool Package and procedure heavy schemas Licensed tools, quoted Bare NUMBER needs a decision
Ispirer Automated conversion of schema, data and code Large estates with a services budget Quoted per project Scope and review time drive the price
DBConvert, dbForge Desktop copy and sync between two databases A single DBA, a single database Per-seat license Runs on a workstation, no audit trail
Oracle GoldenGate Redo-log replication with MySQL as a target Shops already licensed for GoldenGate Oracle license, quoted Another Oracle contract to exit
Fivetran Managed Oracle connector to a MySQL destination Teams already on Fivetran Monthly active rows, plus $5 base per connection MySQL destination is in Beta
Debezium plus JDBC sink Oracle LogMiner CDC to Kafka to MySQL Organizations already on Kafka Infrastructure and engineering time ARCHIVELOG and supplemental logging
Adapters Declared column mapping, incremental sync, per-record logs Typed MySQL tables fed from Oracle on a flat bill Flat monthly from $49, not metered by rows Does not convert PL/SQL

The MySQL Workbench row deserves a second look, because it is where most planning goes wrong. Workbench is the tool people expect to use, it is free, and several of the guides ranking for this search walk through choosing Oracle in its wizard. MySQL's own manual lists the sources it supports, and Oracle is not on the list. For what a cutover of this size costs once the tool is chosen, see what a data migration really costs, and for the same converter-default problem from a different source, the SQL Server to MySQL migration tools page.

Six numbers to know before you sign anything

7

Source databases MySQL Workbench lists as supported for migration. Oracle is not among them and goes through generic ODBC instead.

MySQL Workbench manual, read 1 Oct 2026

9 vs 6

Fractional-second digits an Oracle TIMESTAMP can hold against the most a MySQL DATETIME can hold. Anything past six rounds.

Oracle 19c SQL reference and MySQL 8.4 manual, read 1 Oct 2026

'' = NULL

Oracle treats a zero-length string as null. MySQL keeps it as a value, so the same INSERT means two different things.

Oracle 19c SQL reference, read 1 Oct 2026

4712 BC

Where Oracle's DATE range starts. MySQL DATETIME starts at 1000-01-01, so placeholder and historical dates need a decision.

Oracle 19c SQL reference and MySQL 8.4 manual, read 1 Oct 2026

Once

How often you can set lower_case_table_names: when the server is initialized. AWS SCT needs it at 1 on RDS and Aurora.

MySQL 8.4 manual and AWS SCT guide, read 1 Oct 2026

38

Maximum precision of an Oracle NUMBER in decimal digits. A MySQL BIGINT holds 19, so wide integer keys need DECIMAL.

Oracle 19c SQL reference, read 1 Oct 2026

Eight ways this migration goes wrong while every check stays green

Both engines are relational and both enforce types, so teams expect a clean move. The trouble sits where the two disagree about meaning: each value is legal on both sides and simply means something different after it lands.

The failure What you see What is actually happening
Times of day vanish Row counts and dates match Oracle DATE was declared as MySQL DATE, so every hour, minute and second was dropped on load.
Totals drift by cents Table data reconciles to the penny Converted procedures declare NUMBER parameters as DOUBLE, so the arithmetic they do is approximate.
NULL reports undercount Fewer missing values than before cutover Oracle turned '' into NULL. MySQL stores blanks, so new rows hide from IS NULL checks.
Customers merged One missing row per case or accent pair utf8mb4_0900_ai_ci treats SMITH and Smith as equal, and INSERT IGNORE dropped the second one.
Keys overflow First large insert fails months later NUMBER(10) went to INT and NUMBER(19) to BIGINT, and both reach values the target cannot hold.
Hours shift by region Every timestamp plausible TIMESTAMP WITH TIME ZONE lost its zone, so local times from different offsets compare as one.
Report order changes Same rows, different first page Oracle sorts NULLs last in ascending order by default. MySQL sorts them first, so paginated lists move.
IDs collide after cutover First insert fails on the primary key The sequence became AUTO_INCREMENT, but nobody set its start above the highest loaded value.

Five of the eight are fixed in the DDL or the server settings before the first row moves. The empty-string rule and the NULL ordering are application decisions, and the sequence reset belongs in the cutover runbook. If MySQL is a stop on the way to a warehouse, the warehouse leg is covered on Oracle to Snowflake migration tools.

Six steps that decide whether this migration works

Step 1

Inventory the risky types on Oracle

One query against ALL_TAB_COLUMNS lists every bare NUMBER, every DATE, every TIMESTAMP WITH TIME ZONE and every CLOB in the schema. That list is the real scope, and it is shorter than the table count suggests.

Step 2

Decide the MySQL server settings first

Character set, default collation and lower_case_table_names must be right before the instance holds data. On RDS and Aurora that means a parameter group attached at creation, not afterwards.

Step 3

Write or correct the DDL by hand

Let SCT or SQLines generate a draft, then fix the types on this page: DATETIME for DATE, DECIMAL with measured precision for NUMBER, a UTC column for zoned timestamps. Check every converted procedure signature for DOUBLE.

Step 4

Settle the empty-string rule

Oracle never stored an empty string, so the application never had to decide. Pick per column: allow blanks, block them with a CHECK constraint, or convert them to NULL in the application layer.

Step 5

Full load, then change capture to cutover

Load history once, then follow the Oracle redo log until the switch so cutover takes minutes. Log-based capture needs ARCHIVELOG mode and supplemental logging, which is a DBA ticket to raise early.

Step 6

Reconcile values, then reset the counters

Compare SUM on every numeric column, MIN and MAX on every date, and counts of rows with a non-midnight time. Then set each AUTO_INCREMENT above its loaded maximum and insert one test row per table.

Step five is where a subscription earns its keep or does not. If the move is one weekend, DMS does it and you are done. If Oracle stays live for months while PL/SQL is rewritten, you need the same mapping running every few minutes with a log of every record, which is what a flat Adapters plan covers without counting rows.

Why US teams fund this project

Leaving Oracle licensing

The reason we hear most. An application database that uses few Oracle-specific features carries a support renewal finance asks about every year, and MySQL on RDS or Aurora removes it.

Consolidating on a MySQL stack

A company that acquired an Oracle-backed product and runs everything else on MySQL wants one engine to back up, patch, monitor and hire for.

Feeding a MySQL web application

An ERP stays on Oracle while a customer portal or storefront built on MySQL needs its orders, invoices and accounts every few minutes.

Moving to Aurora MySQL

Teams already on AWS move an Oracle workload into a managed MySQL-compatible engine, usually with SCT for the schema and something else for the ongoing data.

Splitting a monolith

One Oracle schema served five applications. Two of them move to their own MySQL databases first, and their tables must stay current until the rest follow.

Running both during a long cutover

PL/SQL rewrites take a quarter, not a weekend, so Oracle stays the system of record while MySQL is kept current and checked against it until the switch.

Five jobs where you should not pick us

A comparison page that never says the competition wins is an advert. These are the cases where something else on this page is the right answer.

  • This is a one-time move inside AWS with a fixed cutover date. SCT for the schema and DMS for the data is the documented path, it bills by the hour, and a subscription adds nothing once the switch is done.
  • Your schema is mostly PL/SQL packages, procedures and triggers. That is a code conversion project. SQLines, Ispirer or AWS SCT with its extension pack are built for it, and we do not convert procedural code at all.
  • You already own GoldenGate. Pointing an existing GoldenGate deployment at a MySQL target is less work than adopting anything new, at least until the Oracle contract itself is the thing you are exiting.
  • You already run Kafka and Debezium. Turning on the Oracle connector and adding a JDBC sink covers this route, and a vendor adds little to a pipeline your team already operates.
  • You need sub-second latency from an Oracle commit to a MySQL row. Streaming replication built for that job will beat our scheduled sync.

Four questions to ask any vendor on this list

Question 01

Can I see the DDL before anything loads?

Ask for the generated CREATE TABLE statements for your five riskiest tables and read the types yourself. If the tool creates tables automatically at load time, you are accepting its defaults, and the table above lists what those tend to be.

Question 02

What happens to a bare NUMBER and to DATE?

Two questions that sort vendors quickly. A good answer is that bare NUMBER is profiled and given a DECIMAL, and DATE always becomes DATETIME. An answer that mentions DOUBLE or MySQL DATE tells you where the reconciliation will fail.

Question 03

How do you reconcile, and on what?

Row counts are the wrong answer. Ask whether the tool compares sums, date ranges and key hashes per table, and whether it keeps a per-record log you can show an auditor when a number is questioned.

Question 04

What does it cost when volume doubles?

Rows, events, credits and instance hours all grow with data. Ask for the bill at twice your current volume and during the month of the initial full load, which is often the most expensive month of the contract.

Questions buyers ask about Oracle to MySQL migration

How do I migrate from Oracle to MySQL?
Convert the schema first with a tool that shows its type choices, then correct the DDL by hand: DATETIME for Oracle DATE, DECIMAL with real precision for NUMBER, a UTC column plus a zone column for TIMESTAMP WITH TIME ZONE, and a decision on empty strings. Then run a full load, follow changes until cutover, and reconcile on values rather than row counts.
What is the best Oracle to MySQL migration tool?
It depends on the job. AWS SCT plus DMS is the standard pairing for a one-time move into RDS or Aurora MySQL. SQLines and Ispirer convert PL/SQL packages and procedures. GoldenGate suits shops already licensed for it. For an ongoing sync into typed MySQL tables, use a tool that lets you declare the target columns yourself.
Can MySQL Workbench migrate Oracle to MySQL?
Not as a supported source. The MySQL Workbench manual lists SQL Server, Access, MySQL, PostgreSQL, SQL Anywhere, SQLite and Sybase ASE as supported. Oracle can only go through the generic ODBC path, which the manual says is "less automatic". Several guides tell you to pick Oracle in the wizard. Budget for manual type work if you try it.
Does AWS DMS support Oracle to MySQL?
Yes. DMS supports Oracle as a source and MySQL, RDS for MySQL and Aurora MySQL as targets, with a full load followed by ongoing replication. It moves tables and data, not the PL/SQL, so it is normally paired with AWS SCT for the schema and code. SCT also needs lower_case_table_names set to 1 on the target before it is created.
What is the MySQL equivalent of Oracle NUMBER?
It depends on the declaration. NUMBER(p,s) becomes DECIMAL(p,s). NUMBER(p) with no scale becomes the smallest integer type that holds p digits, and DECIMAL(p,0) above 18 digits. A bare NUMBER has no fixed precision, so profile the data and pick a DECIMAL. Avoid DOUBLE, which MySQL documents as approximate.
What is the MySQL equivalent of Oracle DATE?
DATETIME. Oracle documents that every DATE value stores year, month, day, hour, minute and second. MySQL DATE stores only the calendar date, so a DDL script that matches on the type name drops every time of day without an error. Oracle dates before 1000-01-01 also fall below the range MySQL supports for DATETIME.
How do I convert Oracle sequences to MySQL?
MySQL has no CREATE SEQUENCE, so a sequence used for a primary key becomes an AUTO_INCREMENT column on that table, and the trigger that filled it is dropped. After the load, set each AUTO_INCREMENT above the highest loaded value. A sequence shared across several tables needs a small counter table or application logic instead.
Does MySQL treat empty strings as NULL like Oracle?
No. Oracle documents that it "treats a character value with a length of zero as null", so an empty string never exists there. MySQL stores an empty string as a real value distinct from NULL. After cutover the application can write blanks that IS NULL checks, NOT NULL constraints and reports all miss. Decide per column before the switch.
How much does an Oracle to MySQL migration cost?
The tool is usually the small part. AWS SCT has no charge, DMS bills by instance hour, and code converters such as SQLines and Ispirer are quoted per project. The real cost is engineering time on PL/SQL and on testing. An ongoing sync during a long cutover is a monthly subscription, which on Adapters starts at $49 and is not metered by rows.
Can Oracle GoldenGate replicate to MySQL?
Yes. GoldenGate supports MySQL as a target and reads the Oracle redo log, so it can keep MySQL current through a long cutover. It is licensed and operated like any other Oracle product, which makes it a natural fit for a team that already owns it and an expensive one for a team trying to leave Oracle.

For the wider vendor landscape see the best data integration tools, and for the procedural half of an Oracle exit, the PL/SQL conversion guide lists the constructs that convert cleanly and still return different results.

Keep MySQL in step with Oracle until the day you switch

Declare the columns once with DATETIME for DATE and DECIMAL where Oracle had NUMBER, run the backfill, then let the same mapping sync incrementally with retries and per-record logs. From $49 a month, not metered by rows.

The live demo needs no card, and Starter is $49 a month.

Get started