Ilustración editorial de una migración de MySQL 5.6 a 8.0 mostrando riesgos heredados como mezclas de collation, procedimientos almacenados antiguos, triggers viejos, restore frágil y problemas de diseño acumulado.

Publicado: 2026-03-20 · Lectura estimada: 13 min

Categoría: MySQL/MariaDB · Autor: REACT!V® — Victor Cid

Tipos de datos, procedimientos, collations, ancho de fila, engines heredados y otras sorpresas que suelen aparecer cuando una migración se planifica con demasiada fe y poco inventario.

Migrar de MySQL 5.6 a 8.0 suena simple cuando alguien lo resume como “actualizar la base”. En la práctica, la expresión correcta suele ser otra: revisar una herencia técnica que lleva años acumulando decisiones viejas, excepciones que nadie documentó y una confianza excesiva en que si el dump restauró, entonces todo está bien.

Lo primero que conviene asumir es esto: una migración de 5.6 a 8.0 no es un trámite cosmético. Entre medio cambiaron collations, comportamientos del optimizador, validaciones, defaults, motores, funciones toleradas y expectativas de compatibilidad que antes se sostenían más por costumbre que por diseño correcto.

⚠️ Nota importante: MySQL no soporta salto directo de 5.6 a 8.0 mediante upgrade in-place. El camino obligado es 5.6 → 5.7 → 8.0. Quienes intentan saltar directo suelen llevarse una sorpresa en producción.

Paso previo obligatorio: el inventario

Antes de tocar cualquier dump, el trabajo real empieza con un inventario honesto. Esto no es opcional:

sql-- Listar engines por tabla
SELECT table_name, engine
FROM information_schema.tables
WHERE table_schema = 'tu_base_de_datos';

-- Revisar collations por tabla y columna
SELECT table_name, column_name, character_set_name, collation_name
FROM information_schema.columns
WHERE table_schema = 'tu_base_de_datos'
 AND character_set_name IS NOT NULL;

-- Listar routines, triggers y views
SELECT routine_type, routine_name, sql_mode
FROM information_schema.routines
WHERE routine_schema = 'tu_base_de_datos';

SELECT trigger_name, event_manipulation, sql_mode
FROM information_schema.triggers
WHERE trigger_schema = 'tu_base_de_datos';

También conviene ejecutar el mysqlcheck antes de cualquier migración:

bashmysqlcheck --all-databases --check --auto-repair -u root -p

Y desde MySQL 5.7.14+ existe el Upgrade Checker oficial:

bashmysqlsh -- util checkForServerUpgrade root@localhost:3306 --outputFormat=JSON

Este checker detecta: keywords reservadas nuevas en 8.0, uso de utf8 (alias de utf8mb3), funciones obsoletas, sql_mode incompatibles y más.

Tipos de datos y diseño heredado

Los tipos de datos suelen ser uno de los primeros focos de sorpresa. Tablas con varchar(1000) por costumbre, columnas que deberían ser text, definiciones demasiado anchas para lo que realmente almacenan y diseños heredados que funcionaban solo porque nadie los había tensionado con criterios más estrictos.

El problema concreto: MySQL 8.0 tiene un límite de ancho de fila de 65,535 bytes para tablas InnoDB en modo COMPACT/REDUNDANT. Si tienes varias columnas varchar anchas en la misma tabla, puedes golpear ese límite al recrear el esquema.

sql-- Detectar tablas con riesgo de row size overflow
SELECT table_name,
 SUM(character_maximum_length) AS estimated_row_width
FROM information_schema.columns
WHERE table_schema = 'tu_base'
 AND data_type IN ('varchar','char')
GROUP BY table_name
HAVING estimated_row_width > 8000
ORDER BY estimated_row_width DESC;

Routines, triggers y sótanos técnicos

Otro clásico son los procedimientos almacenados, funciones y triggers. Muchas bases antiguas los tienen como sótano técnico: útiles, sí, pero llenos de decisiones viejas, estilos inconsistentes y supuestos que nadie volvió a validar.

Un problema específico que aparece poco documentado: las routines en MySQL almacenan el sql_mode vigente al momento de su creación. Si el procedure fue creado en 5.6 con sql_mode='' (permisivo) y en 8.0 el modo es STRICT_TRANS_TABLES,NO_ZERO_DATE,..., el procedure puede comportarse distinto al ser recreado.

sql-- Ver el sql_mode con que fue creado cada routine
SELECT routine_name, sql_mode
FROM information_schema.routines
WHERE routine_schema = 'tu_base';

Si al recrear el procedure en 8.0 cambia su sql_mode, errores como ERROR 1264: Out of range value o ERROR 1365: Division by 0 pueden aparecer donde antes no existían.

Charset, collation y restores mal queridos

Después aparece el capítulo de charset y collation. No es raro encontrar mezclas de latin1, utf8 antiguo (que en 8.0 se renombra a utf8mb3 y queda deprecated), utf8mb4, collations heredadas y aplicaciones que suponen una cosa mientras la base almacena otra.

El cambio más silencioso: el collation por defecto para utf8mb4 cambió de utf8mb4_general_ci (5.6/5.7) a utf8mb4_0900_ai_ci (8.0). Esto afecta comparaciones, ordenamientos y queries que asumen un collation implícito.

sql-- Detectar mezclas de collation que generarán "Illegal mix of collations"
SELECT
 a.table_name, a.column_name, a.collation_name,
 b.table_collation AS table_default_collation
FROM information_schema.columns a
JOIN information_schema.tables b
 ON a.table_schema = b.table_schema AND a.table_name = b.table_name
WHERE a.table_schema = 'tu_base'
 AND a.collation_name != b.table_collation
 AND a.collation_name IS NOT NULL;

Para migrar datos en latin1 con caracteres no-ASCII a utf8mb4 de forma segura:

sql-- NO hacer esto (convierte bytes, no semántica):
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4;

-- Hacer esto (preserva los bytes originales primero):
ALTER TABLE t MODIFY col VARBINARY(255);
ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Engines heredados: MyISAM y el olvido

MySQL 8.0 no elimina MyISAM, pero lo deja como ciudadano de segunda clase: sin soporte de transacciones, sin crash recovery confiable, sin foreign keys. Si tienes tablas críticas en MyISAM, la migración es el momento de convertirlas — no después.

sql-- Listar tablas MyISAM (o MEMORY, CSV, etc.)
SELECT table_name, engine, table_rows
FROM information_schema.tables
WHERE table_schema = 'tu_base'
 AND engine != 'InnoDB';

-- Convertir a InnoDB
ALTER TABLE nombre_tabla ENGINE = InnoDB;

SQL mode: el comportamiento que cambia sin avisar

MySQL 8.0 tiene un sql_mode por defecto más estricto. Los modos que se agregan por defecto incluyen: STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION.

Esto rompe silenciosamente:

  • Insertar '0000-00-00' como fecha válida
  • Dividir por cero sin error (retornaba NULL en 5.6)
  • Insertar strings en columnas numéricas sin truncation error
sql-- Ver el sql_mode actual
SELECT @@GLOBAL.sql_mode;

-- Temporalmente permisivo para diagnóstico (NO dejar en producción)
SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';

Riesgos críticos resumidos

ÁreaRiesgo concretoHerramienta de diagnóstico
Tipos de datosRow size overflow en varchar anchosinformation_schema.columns
Routines/Triggerssql_mode distinto al recrearinformation_schema.routines
Charset/CollationIllegal mix of collations, datos gibberishQuery de collation cruzada
EnginesMyISAM sin transacciones ni recoveryinformation_schema.tables
SQL modeInserciones rotas, divisiones por cero@@GLOBAL.sql_mode
Upgrade pathNo existe salto directo 5.6→8.0mysqlsh Upgrade Checker
Script de restoreRestore irreproducible sin charset explícitoValidación en staging

Lo que este artículo no cubre (y por qué)

Replicación master-slave durante la migración: es un escenario válido pero requiere su propio artículo — las implicancias de replicar entre versiones distintas tiene suficientes aristas para no tratarlo a medias aquí.

Migración desde MariaDB a MySQL 8.0: aunque comparten historia, MariaDB ha divergido significativamente (system-versioned tables, funciones propias). Ese camino merece tratamiento separado.

Tuning de rendimiento post-migración: el optimizador de 8.0 cambió el manejo de query plans. Hay casos documentados donde queries que rendían bien en 5.6 degradan en 8.0 por diferencias en el cost model. Ese tema es suficientemente amplio para no abordarlo de paso.

Conclusión

La migración sana no parte por el dump. Parte por el inventario. Cuando haces eso, la migración deja de parecer una apuesta y empieza a parecer una intervención técnica seria. Lo peligroso rara vez es lo que sabes que está mal; lo peligroso es lo que lleva años funcionando apenas lo suficiente como para que nadie lo mire.

Si este problema aparece en tu entorno, conversemos antes de que escale.