PostgreSQL to MySQL Converter
Paste PostgreSQL SQL - a pg_dump schema, CREATE TABLE statements or everyday queries - and get MySQL 8.0+ compatible SQL. The converter parses table bodies structurally, so it maps SERIAL and IDENTITY columns to AUTO_INCREMENT, BOOLEAN to TINYINT(1), JSONB to JSON, UUID to CHAR(36) with DEFAULT (UUID()), TIMESTAMPTZ to DATETIME(6) or TIMESTAMP, and inlines CREATE TYPE ... AS ENUM values into ENUM(...) columns. Queries get ON CONFLICT rewritten to ON DUPLICATE KEY UPDATE or INSERT IGNORE, STRING_AGG to GROUP_CONCAT, || to CONCAT(), ILIKE to LIKE and :: casts to CAST(). pg_dump noise such as SET, OWNER TO, GRANT and CREATE EXTENSION is removed, and every change that is not a straight equivalent is listed as a warning so nothing disappears silently. Everything runs in your browser; your schema never leaves the page.
- CREATE EXTENSION pgcrypto removed - MySQL has no extensions; check that nothing depends on its functions or types.
- users.public_id: expression DEFAULT UUID() wrapped in parentheses - expression defaults need MySQL 8.0.13+.
- users.settings: JSON cannot have a literal DEFAULT - rewritten as an expression default ('{}'), which needs MySQL 8.0.13+.
- users.tags: array type text[] mapped to JSON - MySQL has no array columns; store a JSON array and query it with JSON_CONTAINS() or MEMBER OF().
- ALTER ... OWNER TO statements dropped - MySQL has no object owners; use GRANT.
- users_settings_gin: USING GIN index has no MySQL equivalent and was commented out - use a FULLTEXT index for text search, a multi-valued index (CAST(col->'$' AS UNSIGNED ARRAY)) for JSON arrays, or SPATIAL for geometry.
- GRANT/REVOKE statements dropped - PostgreSQL roles and privileges do not map to MySQL accounts; re-create them with MySQL GRANT.
- Dropped PostgreSQL session settings: statement_timeout, client_encoding, set_config() (SET search_path / pg_dump SET lines have no MySQL meaning).
- TIMESTAMPTZ -> DATETIME on users.created_at: DATETIME stores no time zone - write UTC consistently (e.g. SET time_zone = '+00:00') or choose the TIMESTAMP option.
- 2 PostgreSQL :: cast(s) removed or rewritten as CAST(... AS ...) - MySQL converts most literals implicitly.
Do more than postgresql to mysql converter — meet Chat2DB
Chat2DB is an AI-powered SQL client for Windows, macOS and Linux. Write SQL in natural language, format and optimize queries automatically, and manage MySQL, PostgreSQL, Oracle and 20+ other databases in one workspace.
PostgreSQL to MySQL type mapping
| PostgreSQL | MySQL 8.0+ |
|---|---|
| SERIAL / BIGSERIAL / SMALLSERIAL | INT / BIGINT / SMALLINT AUTO_INCREMENT |
| GENERATED ... AS IDENTITY | AUTO_INCREMENT |
| BOOLEAN (TRUE / FALSE) | TINYINT(1) (1 / 0) |
| VARCHAR (no length) | VARCHAR(255) |
| TEXT | TEXT (no literal DEFAULT before 8.0.13, key needs a prefix) |
| BYTEA | LONGBLOB |
| TIMESTAMP(p) [WITHOUT TIME ZONE] | DATETIME(p) |
| TIMESTAMPTZ | DATETIME(6) or TIMESTAMP(6) |
| JSON / JSONB | JSON |
| UUID + gen_random_uuid() | CHAR(36) DEFAULT (UUID()) |
| DOUBLE PRECISION / REAL | DOUBLE / FLOAT |
| NUMERIC(p,s) / MONEY | DECIMAL(p,s) / DECIMAL(19,4) |
| INET / CIDR | VARCHAR(43) |
| int[] / text[] | JSON |
| CITEXT | VARCHAR(255) with a _ci collation |
| CREATE TYPE ... AS ENUM | inline ENUM(...) on each column |
The converter is best-effort: it doesn't rewrite functions, triggers or $$-quoted bodies, and anything it can't translate exactly shows up in the warnings list.
How to use
- Paste PostgreSQL DDL, pg_dump output or queries into the input box, or load one of the samples.
- Pick the options: strip the public. schema prefix, append ENGINE=InnoDB DEFAULT CHARSET=utf8mb4, choose DATETIME(6) or TIMESTAMP for TIMESTAMPTZ columns, and the upsert style.
- Copy the MySQL output, read every warning, and run the script against a MySQL 8.0+ test database before production.
Frequently asked questions
How are SERIAL, IDENTITY and sequences converted to MySQL?
SERIAL, BIGSERIAL and SMALLSERIAL become INT, BIGINT and SMALLINT with AUTO_INCREMENT, and GENERATED ALWAYS/BY DEFAULT AS IDENTITY becomes AUTO_INCREMENT too. MySQL requires an AUTO_INCREMENT column to be the first column of a key, so the converter folds a later ALTER TABLE ... ADD PRIMARY KEY (the pg_dump layout) back into the CREATE TABLE and warns if the column is still not a key. Standalone CREATE SEQUENCE statements are removed with a warning, and pg_dump setval() calls become ALTER TABLE ... AUTO_INCREMENT = n.
What is the MySQL equivalent of ON CONFLICT DO UPDATE?
INSERT ... ON DUPLICATE KEY UPDATE. EXCLUDED.col becomes VALUES(col), or new.col with the row-alias style (INSERT ... VALUES (...) AS new) available since MySQL 8.0.19. The important difference is the conflict target: MySQL fires the update for a duplicate on any unique index or the primary key, not only the columns listed in ON CONFLICT (...). ON CONFLICT DO NOTHING becomes INSERT IGNORE, which also downgrades other errors to warnings, so the tool flags both cases.
Can I migrate the data as well as the schema?
This page converts SQL text, including COPY ... FROM stdin blocks from a plain-format pg_dump, which it turns into multi-row INSERT statements. For a live database-to-database move, Chat2DB connects to both PostgreSQL and MySQL, lets you compare schemas side by side and has an AI assistant that rewrites vendor-specific SQL - try it in the browser at https://app.chat2db.ai or download it from https://chat2db.ai/download.
