---
title: "Convertir MySQL a PostgreSQL"
description: "Convierte un volcado de MySQL o MariaDB en un script de PostgreSQL que carga a la primera, con un informe de cada cambio. En tu navegador: el volcado nunca se sube."
canonical: https://intosql.com/es/mysql-a-postgresql
last_updated: 2026-10-15
---

# Convertir MySQL a PostgreSQL

Suelta un volcado de mysqldump, mariadb-dump, mysqlpump, phpMyAdmin o Adminer, en .sql o .sql.gz, y descarga un script de PostgreSQL con las mismas tablas, claves, índices y datos. Cada valor que PostgreSQL no puede guardar tal cual, y cada objeto que no admite, aparece en el informe.

## Qué cambia de MySQL a PostgreSQL

Cada fila es una regla que aplica el convertidor, con la línea que escribe en el informe cuando la regla cambia algo en tus datos.

| En MySQL | En PostgreSQL | Línea del informe |
| --- | --- | --- |
| TINYINT(1), BOOL | boolean cuando cada valor es 0 o 1, si no smallint | `bool_kept_numeric` |
| UNSIGNED integers | el siguiente entero más amplio con un CHECK de que no sea negativo; BIGINT UNSIGNED es bigint cuando cada valor cabe, si no numeric(20,0) | `unsigned_widened` |
| ZEROFILL and display widths | se descarta | `zerofill_dropped` |
| FLOAT(M,D) | real o double precision, sin la escala | `float_scale_dropped` |
| BIT(1), BIT(n) | boolean, bit(n) |  |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULL | `invalid_date_null` |
| NOT NULL columns with values that become NULL | sin NOT NULL | `not_null_relaxed` |
| DEFAULT '0000-00-00' | sin valor predeterminado | `zero_date_default` |
| TIME | time cuando cada valor cabe en un día, si no interval | `time_as_interval` |
| YEAR | smallint con un CHECK de su rango |  |
| CHAR(n) | varchar(n) |  |
| DATETIME | timestamp |  |
| TIMESTAMP | timestamptz en la zona horaria que indica el volcado, UTC si no indica ninguna | `timestamp_zone_assumed` |
| ENUM | text con un CHECK de sus valores |  |
| ENUM holding '' (MySQL's error value) | el valor vacío, que el CHECK admite | `enum_invalid_value` |
| ENUM or SET holding values outside its list | sin CHECK | `enum_check_skipped` |
| SET | text[] con un CHECK de que cada elemento esté en la lista |  |
| JSON | jsonb; json cuando un valor contiene \u0000 | `json_not_jsonb` |
| NUL bytes in text | se quita | `nul_removed` |
| text that isn't valid in its character set | los bytes incorrectos como carácter de reemplazo | `invalid_utf8_replaced` |
| text decoded twice (Ã±) | se copia tal cual | `mojibake_suspected` |
| AUTO_INCREMENT | GENERATED BY DEFAULT AS IDENTITY, con el contador después de los ids copiados |  |
| MyISAM AUTO_INCREMENT on the second column of a key | un contador para la tabla | `myisam_group_autoincrement` |
| ON UPDATE CURRENT_TIMESTAMP | un disparador BEFORE UPDATE | `on_update_trigger` |
| generated columns | STORED | `virtual_as_stored` |
| generated columns with functions PostgreSQL lacks | una columna simple | `generated_not_translated` |
| INVISIBLE columns | columnas normales | `invisible_column` |
| CHECK constraints | traducido, en línea en CREATE TABLE |  |
| CHECK constraints with functions PostgreSQL lacks | no se crea | `check_skipped` |
| CHECK ... NOT ENFORCED | no se crea | `check_not_enforced` |
| defaults with functions PostgreSQL lacks | sin valor predeterminado | `default_not_translated` |
| keys and indexes on a prefix, c(20) | un índice sobre left(c, 20) | `prefix_unique` |
| FULLTEXT indexes | GIN sobre to_tsvector('simple', ...) | `fulltext_as_gin` |
| indexes on values over 2,000 bytes | hash | `index_on_wide_values` |
| SPATIAL indexes | no se crea sin PostGIS | `spatial_index_skipped` |
| functional indexes PostgreSQL can't write | no se crea | `index_skipped` |
| foreign keys | después de los datos, NOT VALID, luego validada con una advertencia si hay huérfanas |  |
| foreign keys to columns without a unique key | no se crea | `foreign_key_skipped` |
| table and column names | en minúsculas cuando siguen siendo únicos | `identifier_renamed` |
| names over 63 bytes | acortado con un hash | `name_shortened` |
| GEOMETRY, POINT, POLYGON... | WKB en bytea | `geometry_as_wkb` |
| INET4, INET6, UUID (MariaDB) | inet, uuid |  |
| BINARY, VARBINARY, BLOB | bytea |  |
| PARTITION BY | una sola tabla | `partitions_dropped` |
| WITH SYSTEM VERSIONING (MariaDB) | una tabla con las filas actuales | `system_versioning_dropped` |
| MyISAM, MEMORY and other engines | una tabla normal | `engine_dropped` |
| views, triggers, procedures, functions and events | listados en el informe | `not_converted_objects` |
| dumps without CREATE TABLE | tipos leídos de los valores | `no_schema` |
| geometries in a dump without CREATE TABLE | WKB en bytea | `geometry_inferred` |
| _ci collations | comparación exacta | `case_insensitive_collation` |
| SET NAMES utf8 from utf8mb4 tables | se convierte, con una advertencia | `dump_lost_four_byte_chars` |
| dumps without SET NAMES whose text isn't UTF-8 | se lee como Latin-1 (Windows-1252) | `charset_guessed` |
| sjis, cp932, gbk, big5 dumps | se lee como UTF-8, con una advertencia | `unsupported_charset` |
| UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows | se evalúan |  |
| other expressions in rows | NULL | `expression_value` |
| DEFAULT in VALUES | el valor predeterminado de la columna | `default_keyword_filled` |
| DEFAULT in VALUES without a literal default | NULL | `default_keyword_null` |
| REPLACE and INSERT IGNORE | filas simples | `replace_as_insert` |
| types IntoSQL doesn't know | text | `unknown_type` |
| values that don't fit their column | NULL | `invalid_value_null` |
| unreadable geometries | NULL | `bad_geometry` |
| CREATE SEQUENCE (MariaDB) | CREATE SEQUENCE con su valor actual |  |

## Carga el script en PostgreSQL

El script crea las tablas, copia las filas y luego agrega claves, índices y claves foráneas, así que carga rápido y se detiene en el primer error.

```shell
psql -v ON_ERROR_STOP=1 -d mydb -f mysql.postgresql.sql
```

Las claves foráneas se agregan como NOT VALID y luego se validan. Si una fila apunta a una fila que no existe, el script te dice qué restricción es, en lugar de fallar a medias.

Para un volcado grande, crea primero la base de datos y ejecuta el script con psql desde la misma máquina que el servidor.

## Haz el volcado de MySQL para el mejor resultado

El convertidor lee lo que contiene el volcado. Estas opciones conservan más de tus datos en él:

- --default-character-set=utf8mb4 conserva los emoji y otros caracteres de 4 bytes, que un volcado utf8 pierde antes de que el convertidor lo vea.
- --hex-blob escribe las columnas binarias en hexadecimal, que sobrevive a la copia entre sistemas.
- --routines --triggers --events agregan esos objetos al volcado, para que el informe pueda listarlos.

## Qué no se convierte

Las vistas, los disparadores, los procedimientos almacenados, las funciones y los eventos se escriben en el lenguaje propio de cada base de datos. Aparecen en el informe por nombre, nunca se descartan en silencio, para que puedas reescribirlos para PostgreSQL.

## Comparado con pgloader

Los mismos volcados, convertidos y cargados por IntoSQL y por pgloader 3.6.7 en una sola máquina (un i9-10900K de 10 núcleos con un SATA SSD), en octubre de 2026.

- Una columna TINYINT(1) con 2, -1 y -5: pgloader carga true en cada una, sin advertencia. IntoSQL conserva los números y el informe dice por qué.
- Un volcado con un valor predeterminado 'it's', una tabla con una comilla invertida en el nombre, un ENUM con el valor vacío y un TIME de más de 24 horas: pgloader se detiene. IntoSQL lo convierte y lo carga.
- Lo que carga pgloader pierde sus claves primarias, únicas y foráneas, y sus identidades. IntoSQL las conserva todas.
- Un volcado de 5.3 GB con 30 millones de filas: pgloader necesita restaurarlo antes en un MySQL en ejecución, lo que tarda 18 minutos, y luego se queda sin memoria con su configuración predeterminada. IntoSQL convierte el volcado en 10 segundos, y psql carga el script en unos 3 minutos.
- En 476 volcados de MySQL 5.5 a 9 y MariaDB 10.3 a 12, cargados en PostgreSQL 13 y 18: ningún error de carga, y ningún valor cambió sin una línea en el informe.

## Preguntas sobre MySQL a PostgreSQL

### ¿Se sube mi volcado?

No. El convertidor se ejecuta en tu navegador y lee el volcado de tu disco por partes, así que nunca sale de tu computadora. La app de escritorio y la línea de comandos también convierten en tu computadora.

### ¿Qué tan grande puede ser el volcado?

El convertidor nunca tiene todo el volcado en memoria: lee el archivo dos veces, por rangos, y escribe el script sobre la marcha. Los volcados de varios gigabytes se convierten en el navegador, en la app de escritorio y con la línea de comandos.

### ¿Lee volcados de MariaDB?

Sí. Los volcados de mariadb-dump y de MariaDB 10.3 a 12 se convierten de la misma forma, incluidas las columnas INET6, INET4 y UUID de MariaDB.

### ¿Qué pasa con las fechas 0000-00-00?

PostgreSQL no tiene fecha cero, así que se vuelven NULL y la columna acepta NULL. El informe dice cuántas había en cada columna.

### ¿Se conservan los valores AUTO_INCREMENT?

Sí. Cada columna AUTO_INCREMENT se vuelve una columna de identidad, cada fila conserva su id, y el siguiente id sigue después del más alto, o después del AUTO_INCREMENT de la tabla si es mayor.

### ¿TINYINT(1) se vuelve boolean?

Solo cuando cada valor de la columna es 0 o 1. Si contiene otros números, como 2 o -1, sigue siendo un número y el informe dice por qué, así que ningún valor se vuelve true por accidente.

### ¿Qué pasa con los procedimientos almacenados y los disparadores?

Aparecen en el informe por nombre y no se convierten, porque cada base de datos los escribe en su propio lenguaje. ON UPDATE CURRENT_TIMESTAMP es la excepción: se vuelve un disparador de PostgreSQL.

### ¿En qué versiones de PostgreSQL carga el script?

PostgreSQL 13 a 18. El mismo script carga en cada una, y se detiene en el primer error si algo sale mal.

## Otras conversiones a PostgreSQL

- [Convertir Excel a PostgreSQL](https://intosql.com/es/excel-a-postgresql)
- [Convertir CSV a PostgreSQL](https://intosql.com/es/csv-a-postgresql)
- [Convertir JSON a PostgreSQL](https://intosql.com/es/json-a-postgresql)
