NetSendo
Guides & Tips

Actualizar MySQL 8.0 a 8.4 en Docker Compose sin riesgos

NetSendo Team15 min de lectura
Actualizar MySQL 8.0 a 8.4 en Docker Compose sin riesgos

Para actualizar MySQL 8.0 a 8.4 en Docker, haz una copia de seguridad de la base de datos, cambia la imagen a una etiqueta fija mysql:8.4.x y, en la misma edición, quita la opción --default-authentication-plugin, que 8.4 ya no reconoce. Después ejecuta docker compose up -d y el servidor actualizará el directorio de datos en su primer arranque. Es un camino de ida: un directorio de datos de 8.4 ya no arranca en 8.0, así que la copia de seguridad es tu única vuelta atrás.

En resumen: MySQL 8.0 llegó al final de su vida útil en abril de 2026; 8.4 es la serie LTS a la que debes pasar, y la actualización in situ desde 8.0 está soportada. La mayoría de las actualizaciones en Docker fallan por un solo motivo: 8.4 eliminó default_authentication_plugin, así que una línea command: antigua hace que el contenedor se detenga al instante. Además, 8.4 desactiva mysql_native_password por defecto, de modo que las cuentas creadas en 8.0 con ese plugin no podrán iniciar sesión hasta que lo actives con --mysql-native-password=ON o las pases a caching_sha2_password. Antes de nada: un mysqldump, una copia del volumen detenido y una prueba de restauración.

¿Por qué actualizar de MySQL 8.0 a 8.4 ahora?

Porque MySQL 8.0 ya no recibe mantenimiento: Oracle indica que MySQL 8.0 llegó al final de su vida útil en abril de 2026, con 8.0.46 como última versión de corrección. Un contenedor con 8.0 sigue funcionando, pero ya no recibe parches de seguridad, y cada nueva vulnerabilidad del servidor queda abierta en tu máquina, esté en IONOS, Arsys o Hostinger.

MySQL 8.4 es la serie de soporte a largo plazo (LTS) que sucede a 8.0. Las rutas de actualización oficiales indican que el paso «8.0 → 8.4.x LTS» se puede hacer in situ, mediante volcado lógico y carga, o por replicación. Para un único contenedor lo más sencillo es la actualización in situ: arrancas la nueva imagen sobre el volumen antiguo y el servidor actualiza por sí mismo el diccionario de datos y las tablas del sistema. Lo hace solo desde MySQL 8.0.16, así que no hace falta ejecutar mysql_upgrade por separado.

Dos cosas en Docker Hub lo hacen urgente. Primero, la imagen oficial de mysql ya no incluye una etiqueta 8.0 entre las soportadas; 8.4 y 8 apuntan ahora a 8.4.13. Segundo, las etiquetas flotantes avanzaron: lts apunta a 9.7 y latest a la serie de innovación 26.x. Un compose con image: mysql o mysql:lts sin fijar puede saltarse 8.4 en el próximo docker compose pull y aterrizar en una versión en la que mysql_native_password ya no existe.

⚠️ Atención: Fija siempre la imagen de MySQL a una serie o a una versión de parche (mysql:8.4 o mysql:8.4.13). Un cambio de versión mayor debe ser una decisión tuya con una copia de seguridad en la mano, nunca un efecto secundario de descargar imágenes.

¿Qué falla al cambiar la imagen a mysql:8.4?

Lo más habitual es que el contenedor termine al instante porque su command: sigue pasando --default-authentication-plugin=mysql_native_password, una opción del servidor que 8.4 eliminó. Muchos archivos compose escritos para MySQL 8.0 contienen justo esta línea:

services:
  db:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - dbdata:/var/lib/mysql

Al arrancar con mysql:8.4, el servicio se detiene antes de abrir el directorio de datos y el log muestra:

$ docker compose logs db
db  | [ERROR] [MY-000067] [Server] unknown variable 'default-authentication-plugin=mysql_native_password'.
db  | [ERROR] [MY-010119] [Server] Aborting

Según What Is New in MySQL 8.4, usar una opción eliminada es un error, no un aviso. La buena noticia: el servidor aborta antes de tocar tus datos, así que todavía no se ha actualizado nada. Lo mismo vale para un my.cnf montado en /etc/mysql/conf.d/; revísalo junto con la línea command:.

Opciones eliminadas y sus sustitutos

Eliminado en 8.4Usa en su lugarDónde suele estar en un compose
--default-authentication-plugin--authentication-policycommand:
--skip-host-cache--host-cache-size=0command:, configuraciones antiguas de la imagen
expire_logs_daysbinlog_expire_logs_secondsmy.cnf montado
--ssl, have_ssl--tls-versioncommand:, my.cnf
--no-dd-upgrade--upgrade=NONEpoco habitual

Actualizado a noviembre de 2026. Fuente: MySQL 8.4 Reference Manual, What Is New.

Cambios que no impiden el arranque, pero cambian el comportamiento

  • Autenticación. mysql_native_password está desactivado por defecto en 8.4. Un usuario de la aplicación creado en 8.0 con ese plugin recibe ERROR 1045 (28000): Access denied, y crear una cuenta así falla con ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded. Las dos salidas se explican más abajo.
  • Claves foráneas no estándar. Las claves foráneas que apuntan a una clave no única o parcial se rechazan en nuevos CREATE TABLE mientras restrict_fk_on_non_standard_key esté en ON (por defecto). Las tablas existentes se actualizan sin problema y el servidor registra un aviso por cada una de esas claves. Las migraciones que creen claves nuevas de ese tipo fallarán.
  • Nuevas palabras reservadas. MANUAL, PARALLEL, QUALIFY y TABLESAMPLE pasan a ser reservadas. Una columna llamada manual debe ir entre comillas invertidas en SQL directo; los ORM que siempre entrecomillan los identificadores no se ven afectados.
  • Valores por defecto de InnoDB. Cambiaron varios, lo que importa en un VPS pequeño con discos lentos. Si tu configuración dependía de los valores antiguos, fíjalos de forma explícita.
VariablePor defecto en 8.0Por defecto en 8.4
innodb_io_capacity (operaciones de E/S/s)20010000
innodb_log_buffer_size (MiB)1664
innodb_change_bufferingallnone
innodb_adaptive_hash_indexONOFF
innodb_flush_method (Linux)fsyncO_DIRECT si está soportado
temptable_max_ram (GiB)13 % de la RAM, entre 1 y 4

Actualizado a noviembre de 2026. Fuente: MySQL 8.4 Reference Manual, What Is New.

¿Cómo hacer una copia de seguridad de un contenedor MySQL antes de actualizar?

Haz dos copias: un volcado lógico con mysqldump, que puedes cargar en cualquier versión de MySQL, y una copia del volumen de datos detenido, que es la forma más rápida de volver exactamente al estado que tenías en 8.0. Después, demuestra que el volcado se restaura.

Las dos copias se deben a que la actualización solo va en un sentido. La documentación de MySQL sobre downgrade solo admite volver de 8.4 a 8.0 mediante volcado lógico y carga (o replicación), y únicamente para revertir. Un servidor 8.0 no abre sin más un directorio de datos de 8.4.

Antes de la copia, ejecuta el comprobador de actualización (upgrade checker). Lee el servidor 8.0 en marcha y lista opciones eliminadas, problemas de autenticación, palabras reservadas usadas como identificadores y otras incompatibilidades. MySQL Shell viene en la imagen mysql:8.4, así que no instalas nada; sin --target-version, el comprobador apunta a la propia versión del Shell:

# find the network of your compose project, e.g. myapp_default
docker network ls

# run the 8.4 upgrade checker (MySQL Shell ships in the mysql:8.4 image)
# against the 8.0 server that is still running
docker run --rm -it --network myapp_default mysql:8.4.13 \
  mysqlsh -- util checkForServerUpgrade root@db:3306

Lee cada Error del informe; los avisos sobre mysql_native_password son esperables y se tratan más abajo. Luego detén todo lo que escribe en la base de datos y haz las copias. Sustituye myapp_ por el nombre de tu proyecto compose y los nombres de servicio por los tuyos:

# 1. stop everything that writes to the database (app, workers, scheduler)
docker compose stop app queue scheduler

# 2. logical dump of the application database
docker compose exec -T db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" \
  --single-transaction --routines --triggers --events \
  --databases "$MYSQL_DATABASE"' | gzip > db-before-8.4.sql.gz

# 3. physical copy of the stopped data volume
docker compose stop db
docker volume ls | grep dbdata            # e.g. myapp_dbdata
docker run --rm -v myapp_dbdata:/var/lib/mysql:ro -v "$PWD":/backup alpine \
  tar czf /backup/dbdata-8.0.tgz -C /var/lib/mysql .

El volcado usa --single-transaction, una instantánea coherente de las tablas InnoDB sin bloquearlas, e incluye rutinas, triggers y eventos. La copia del volumen se hace solo después de docker compose stop db: copiar los archivos de un servidor MySQL en marcha da un directorio de datos que quizá no arranque. La guía de preparación de MySQL también pide un apagado limpio antes de actualizar, y docker compose stop lo consigue siempre que el servidor termine dentro del tiempo de parada (10 segundos por defecto; amplíalo con stop_grace_period si tu buffer pool es grande).

Prueba el volcado en un contenedor 8.0 desechable para saber que el archivo está completo antes de necesitarlo:

docker run -d --name restore-test -e MYSQL_ROOT_PASSWORD=test mysql:8.0
docker logs -f restore-test               # wait for "ready for connections", then Ctrl+C
gunzip -c db-before-8.4.sql.gz | docker exec -i restore-test mysql -uroot -ptest
docker exec restore-test mysql -uroot -ptest -e \
  "SELECT table_schema, COUNT(*) AS tables FROM information_schema.tables GROUP BY table_schema;"
docker rm -f restore-test

Saca los dos archivos del servidor o, como mínimo, llévalos a otro disco. Una copia en el mismo disco que la base de datos no te protege si ese disco falla.

📋 Lista de comprobación antes de cambiar la imagen

  • Upgrade checker ejecutado, sin errores sin explicar
  • Archivo de mysqldump creado y restaurado en un contenedor de prueba
  • Volumen detenido copiado en un .tgz
  • Espacio libre en disco para la actualización y las copias
  • docker-compose.yml antiguo guardado como copia

¿Qué hacer con mysql_native_password?

O lo dejas activado por ahora con --mysql-native-password=ON, o pasas todas las cuentas a caching_sha2_password antes de la actualización o justo después. Ambas opciones funcionan en 8.4; solo la segunda funcionará en MySQL 9, donde el plugin ya no existe.

Primero averigua qué cuenta usa qué plugin. Ejecuta esto en el servidor 8.0 antes de actualizar:

SELECT user, host, plugin
FROM mysql.user
ORDER BY plugin, user;

Si todas las cuentas de la aplicación muestran ya caching_sha2_password (el valor por defecto para cuentas nuevas desde MySQL 8.0), no necesitas el plugin nativo: quita la opción antigua, deja la authentication_policy por defecto *,, y listo. Las cuentas con mysql_native_password suelen existir porque el compose forzó ese plugin al crear la base de datos, a menudo por un driver de PHP antiguo.

✅ Ventajas de mantener mysql_native_password

  • Sin cambios en usuarios ni contraseñas; la actualización es solo una edición del compose
  • Funciona con clientes que no hablan caching_sha2_password, como bibliotecas antiguas y algunas compilaciones de las herramientas cliente de MariaDB
  • Se puede desactivar más adelante, cuenta por cuenta

❌ A tener en cuenta

  • El plugin está obsoleto desde 8.0.34 y eliminado en MySQL 9.0, así que solo aplazas el trabajo
  • Su hash basado en SHA-1 es más débil que el de caching_sha2_password, basado en SHA-256
  • El upgrade checker y el log del servidor seguirán avisando

Opción A: mantener la autenticación nativa

Añade --mysql-native-password=ON a las opciones del servidor. Si las cuentas nuevas también deben usar el plugin nativo (por ejemplo, porque el instalador de tu aplicación crea su propio usuario), sustituye la opción eliminada por --authentication-policy=mysql_native_password,,. La referencia de authentication_policy explica el formato: hasta tres factores separados por comas; el primer elemento fija el plugin del primer factor y los elementos vacíos dejan abiertos el segundo y el tercer factor, que son opcionales. La variante más flexible, *:mysql_native_password,,, hace que el nativo sea el predeterminado pero permite otros plugins.

Opción B: pasar las cuentas a caching_sha2_password

Arranca 8.4 con el plugin nativo activado (opción A) para que las cuentas puedan seguir entrando, y cámbialas una a una. Cuando no quede ninguna, reinicia sin la opción:

-- move one account to the 8.4 default plugin (keep or change the password)
ALTER USER 'app_user'@'%' IDENTIFIED WITH caching_sha2_password BY 'the-password';

-- check the result
SELECT user, host, plugin FROM mysql.user WHERE user = 'app_user';

Antes de desactivar el plugin, comprueba que todos los clientes pueden autenticarse así. Los drivers actuales de MySQL para PHP (mysqlnd), Python y Node.js admiten caching_sha2_password. El primer inicio de sesión de una conexión nueva necesita TLS o intercambio de claves RSA; MySQL genera certificados TLS en su primer arranque, así que las conexiones entre contenedores suelen usar TLS sin configurar nada. La sorpresa habitual son las herramientas de copia: si tu contenedor de copias usa el mysqldump de MariaDB, haz un volcado real con la cuenta cambiada antes de quitar el plugin nativo.

Actualizar MySQL 8.0 a 8.4 en Docker Compose paso a paso

Cambia la imagen y las opciones del servidor en una sola edición, arranca solo la base de datos, espera en el log a que termine la actualización del diccionario de datos y luego arranca el resto.

  1. Edita el servicio db

    Fija mysql:8.4.13 (o mysql:8.4 si quieres parches en cada descarga) y sustituye la opción antigua. El ejemplo mantiene la autenticación nativa, la opción segura para una base de datos existente; quita las dos opciones de autenticación si todas tus cuentas ya usan caching_sha2_password.

    services:
      db:
        image: mysql:8.4.13
        command: >-
          --mysql-native-password=ON
          --authentication-policy=mysql_native_password,,
          --character-set-server=utf8mb4
          --collation-server=utf8mb4_unicode_ci
        volumes:
          - dbdata:/var/lib/mysql
  2. Descarga la imagen y arranca solo la base de datos

    Arrancar db por separado evita que la aplicación se conecte mientras el servidor actualiza sus tablas del sistema.

    docker compose pull db
    docker compose up -d db
    docker compose logs -f db
  3. Sigue la actualización en el log

    En el primer arranque el servidor detecta el directorio de datos de 8.0, actualiza el diccionario de datos y los esquemas del sistema y después acepta conexiones. Verás líneas como estas (abreviadas; tus números de versión serán otros):

    [System] [MY-013381] [Server] Server upgrade from '80046' to '80413' started.
    [System] [MY-013381] [Server] Server upgrade from '80046' to '80413' completed.
    [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.4.13'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

    El servidor actualiza metadatos y tablas del sistema, no las filas de tus tablas, así que en una base de datos de aplicación típica es una pausa corta. No detengas el contenedor mientras tanto. Si el log muestra un error, según la documentación de actualización el servidor revierte sus cambios en el directorio de datos; corrige el problema indicado y vuelve a arrancar.

  4. Arranca la aplicación

    Ejecuta docker compose up -d para todo el proyecto. Si la aplicación espera a la base de datos con un healthcheck (mysqladmin ping funciona igual en 8.4), arrancará sola cuando db esté sano.

  5. Guarda el compose antiguo y las copias

    No borres el .tgz ni el volcado hasta pasados unos días de uso normal. Son la única forma de volver.

ℹ️ Nota: docker compose pull nunca edita tu archivo compose. Si una nueva versión de la aplicación trae un docker-compose.yml con mysql:8.4, aun así tienes que copiar ese archivo (o fusionar el servicio db) en tu instalación para que algo cambie.

¿Cómo comprobar que la actualización ha funcionado?

Comprueba cuatro cosas: el servidor informa de 8.4, el juego de caracteres y las intercalaciones no han cambiado, la aplicación inicia sesión y ve todas sus migraciones, y tu comando de copia sigue generando un volcado.

# server version and character set
docker compose exec db mysql -uroot -p -e \
  "SELECT VERSION(); SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'collation_server';"

# table collations per schema (compare with the same query before the upgrade)
docker compose exec db mysql -uroot -p -e \
  "SELECT table_schema, table_collation, COUNT(*) FROM information_schema.tables
   WHERE table_schema NOT IN ('mysql','sys','information_schema','performance_schema')
   GROUP BY 1, 2;"

# the application still sees all its migrations (Laravel example)
docker compose exec app php artisan migrate:status

# a dump still works with the client your backups use
docker compose exec -T db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" \
  --no-data --databases "$MYSQL_DATABASE"' > /dev/null && echo "dump OK"

Compara la consulta de intercalaciones con su resultado de antes de actualizar. Una actualización in situ deja las tablas existentes tal cual; una diferencia suele indicar que una migración recreó una tabla con otros valores por defecto del servidor. Mantén las opciones --character-set-server y --collation-server que usabas en 8.0 para que las tablas nuevas coincidan con las antiguas; con tildes y eñes, quédate en utf8mb4.

Después usa la aplicación: inicia sesión, guarda algo, ejecuta una tarea en segundo plano y lanza una copia programada. Revisa otra vez el log de MySQL en busca de avisos sobre claves foráneas no estándar u opciones obsoletas, y corrígelos mientras recuerdas lo que cambiaste.

📌 Ideas clave

  • Cambia la imagen y el command: a la vez; la opción de autenticación antigua hace que 8.4 se detenga al instante
  • La actualización del diccionario de datos se ejecuta sola en el primer arranque; espera en el log a «completed»
  • Una cuenta con mysql_native_password necesita el plugin activado o pasar a caching_sha2_password
  • Verifica con uso real y una copia real, no solo con SELECT VERSION()

¿Se puede volver de 8.4 a 8.0?

Solo restaurando una copia. MySQL no admite un downgrade in situ de 8.4 a 8.0; la tabla de downgrade solo permite volcado lógico y carga o replicación, y únicamente para revertir cuando no se ha usado ninguna función nueva de 8.4 sobre los datos.

En la práctica hay dos caminos. Si la actualización falló o la aplicación se comporta mal en los primeros minutos, restaura la copia del volumen detenido: recuperas exactamente el estado de 8.0, pero pierdes todo lo escrito después de la copia. Si 8.4 ya lleva un tiempo funcionando y tienes datos nuevos que quieres conservar, haz un mysqldump nuevo en 8.4 y cárgalo en un contenedor 8.0 nuevo y vacío, que es el camino soportado.

docker compose stop
docker compose rm -f db
docker volume rm myapp_dbdata             # deletes the upgraded 8.4 data

# put the old docker-compose.yml back (image: mysql:8.0 and the old command:)
docker compose create db                  # recreates the empty volume
docker run --rm -v myapp_dbdata:/var/lib/mysql -v "$PWD":/backup alpine \
  tar xzf /backup/dbdata-8.0.tgz -C /var/lib/mysql
docker compose up -d
⚠️ Atención: docker volume rm borra los datos para siempre. Ejecútalo solo después de comprobar que dbdata-8.0.tgz existe, no está vacío y que tar tzf dbdata-8.0.tgz | head lista archivos.

Ten en cuenta que volver atrás te deja de nuevo en una versión sin soporte. Úsalo para ganar tiempo mientras corriges lo que bloqueó la actualización, no como destino.

Actualizar la base de datos de una instalación de NetSendo

NetSendo pasó su docker-compose.yml a MySQL 8.4 LTS en la versión 2.2.0 (6 de noviembre de 2026). El servicio db usa ahora image: mysql:8.4 con --mysql-native-password=ON --authentication-policy=mysql_native_password,,, de modo que el usuario de base de datos que creó una instalación en 8.0 sigue entrando, y el mysqldump de MariaDB de la imagen de la aplicación, que usan las copias de NetSendo, puede seguir autenticándose.

Una instalación existente no cambia sola. Descargar una nueva imagen de la aplicación deja tu compose como está, así que la base de datos sigue en 8.0 y funciona con la imagen nueva. Para actualizar, haz una copia de la base de datos, sustituye docker-compose.yml por el de la versión (imagen y command: juntos) y ejecuta docker compose up -d; MySQL actualiza el directorio de datos en el primer arranque. Las notas de la versión describen el camino probado: migraciones en 8.0, el mismo volumen arrancado en 8.4, la aplicación inicia sesión y mysqldump funciona. Los pasos generales de instalación están en el inicio rápido y los ajustes de base de datos del .env en la documentación de configuración.

Si aún estás eligiendo una plataforma para alojar tú mismo, la comparativa de software de email marketing autoalojado muestra qué base de datos necesita cada herramienta y qué implica mantenerla. Respecto al RGPD: autoalojar mantiene los datos en tu propia infraestructura, lo que ayuda con tus obligaciones, pero el cumplimiento depende de cómo gestiones el servidor.

🎯 Consejos de experto

1
Ensaya primero con una copia

Restaura la copia del volumen en un segundo proyecto compose en el mismo host, actualízalo y conecta a él una instancia de pruebas de la aplicación. Diez minutos de ensayo muestran cualquier problema que encontraría la actualización real.

2
En producción, fija la versión de parche

mysql:8.4.13 solo cambia cuando lo editas. Súbela a propósito, después de leer las notas de la versión, y no el día en que alguien ejecute docker compose pull.

3
Planifica ya la salida de mysql_native_password

En 8.4 puede quedarse, pero MySQL 9 lo elimina. Cambiar las cuentas una a una mientras 8.4 funciona estable es mucho más fácil que hacerlo en mitad de la próxima actualización mayor.

4
Dale tiempo al servidor para detenerse

Pon stop_grace_period: 1m en el servicio db. Un servidor MySQL al que se mata tras los 10 segundos por defecto puede necesitar recuperación tras fallo, y un apagado sucio es lo último que quieres justo antes de actualizar.

Preguntas frecuentes

¿Puedo actualizar MySQL 8.0 directamente a 8.4?

Sí. MySQL documenta el paso de 8.0 a 8.4 LTS como soportado: in situ, mediante volcado y carga o por replicación. Desde 5.7 primero hay que pasar por 8.0.

¿Por qué mi contenedor MySQL 8.4 se detiene con «unknown variable 'default-authentication-plugin'»?

MySQL 8.4 eliminó la opción default_authentication_plugin, y usar una opción eliminada detiene el servidor. Quita la opción de command: o de my.cnf y usa --authentication-policy, más --mysql-native-password=ON si tus cuentas aún usan el plugin nativo.

¿Sigue existiendo mysql_native_password en MySQL 8.4?

Sí, pero está desactivado por defecto y hay que activarlo con --mysql-native-password=ON. Está obsoleto y eliminado en MySQL 9.0, así que planifica pasar las cuentas a caching_sha2_password.

¿Puedo volver de MySQL 8.4 a 8.0?

No in situ. MySQL solo admite volver mediante volcado lógico y carga o replicación, para revertir, así que en la práctica restauras la copia hecha antes de actualizar.

¿Me salto 8.4 y paso directamente a MySQL 9.7 LTS?

Puedes, pero MySQL 9 ya no tiene mysql_native_password, así que antes todas las cuentas deben usar caching_sha2_password. En Docker Hub la etiqueta lts apunta a 9.7, por eso conviene fijar la imagen a la versión que has probado.

¿Cuánto tarda la actualización de MySQL 8.0 a 8.4 en Docker?

En el primer arranque el servidor actualiza el diccionario de datos y las tablas del sistema, no las filas de tus tablas, así que en una base de datos típica es una pausa corta. Sigue el log del contenedor hasta que la actualización aparezca como completada y el servidor acepte conexiones.

Fuentes

Lleva tu marketing en tu propio servidor

La configuración Docker de NetSendo ya incluye MySQL 8.4 LTS y mantiene tus datos en tu propia infraestructura.

#mysql#docker#self-hosted#database#upgrade
Compartir