--- title: "Replicación maestro-esclavo en MySQL 8 con Ubuntu 24.04" description: "Configura replicación de MySQL 8.0 entre dos servidores Ubuntu 24.04 con GTID y conexión cifrada, carga los datos iniciales y comprueba que la réplica funciona." category: "Gestión de Bases de Datos" language: es source: https://cubepath.com/es/docs/gestión-de-bases-de-datos/configuracion-de-replicacion-maestro-esclavo-en-mysql updated: 2026-09-25 --- # Replicación maestro-esclavo en MySQL 8 con Ubuntu 24.04 La replicación de MySQL copia de forma continua los cambios de un servidor principal (el origen, antes llamado maestro) a uno o varios servidores réplica (antes llamados esclavos). Sirve para repartir las lecturas, tener un servidor listo si el principal falla y hacer copias de seguridad sin cargar el origen. En este tutorial configurarás una réplica de MySQL 8.0 en Ubuntu 24.04 usando GTID, con el tráfico de replicación cifrado, y comprobarás que los cambios llegan a la réplica. Desde MySQL 8.0.22 los comandos usan la terminología `SOURCE`/`REPLICA` (`START REPLICA`, `SHOW REPLICA STATUS`). Esta guía usa la sintaxis actual. ## Requisitos previos Para seguir esta guía necesitas: - Dos servidores con Ubuntu 24.04 LTS, por ejemplo dos VPS de CubePath, idealmente conectados por una red privada. En los ejemplos: - Origen: `db1`, IP privada `10.0.0.2`. - Réplica: `db2`, IP privada `10.0.0.3`. - Un usuario no root con privilegios `sudo` en ambos. - MySQL Server 8.0 instalado en los dos (`sudo apt install mysql-server`). La réplica debe tener la misma versión o una más reciente que el origen. - UFW activo en ambos servidores. Sustituye `10.0.0.2`, `10.0.0.3` y los nombres de base de datos por los tuyos en todos los comandos. ## Paso 1: Configurar el servidor de origen En `db1`, abre el archivo de configuración de MySQL que usa Ubuntu: ```bash sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf ``` Dentro de la sección `[mysqld]`, cambia `bind-address` para que MySQL escuche en la IP privada y añade las opciones de replicación: ```ini [mysqld] bind-address = 10.0.0.2 server-id = 1 log_bin = /var/log/mysql/mysql-bin.log binlog_expire_logs_seconds = 604800 gtid_mode = ON enforce_gtid_consistency = ON ``` Qué hace cada opción: - `server-id`: identificador único de cada servidor de la topología. - `log_bin`: el registro binario (binlog) guarda los cambios que la réplica descargará. En MySQL 8.0 está activo por defecto; indicar la ruta lo deja explícito. - `binlog_expire_logs_seconds`: borra los binlogs con más de 7 días. Si una réplica se queda desconectada más tiempo, tendrás que volver a cargarla. - `gtid_mode` y `enforce_gtid_consistency`: cada transacción recibe un identificador global (GTID), y la réplica sabe por sí sola desde dónde continuar sin anotar archivos ni posiciones. Si ya existe una línea `bind-address` o `server-id` en el archivo, modifícala en lugar de duplicarla. Reinicia MySQL y comprueba los valores: ```bash sudo systemctl restart mysql sudo mysql -e "SELECT @@server_id, @@gtid_mode, @@log_bin;" ``` ```output +-------------+-------------+-----------+ | @@server_id | @@gtid_mode | @@log_bin | +-------------+-------------+-----------+ | 1 | ON | 1 | +-------------+-------------+-----------+ ``` Permite el puerto 3306 solo desde la réplica: ```bash sudo ufw allow from 10.0.0.3 to any port 3306 proto tcp ``` ## Paso 2: Crear el usuario de replicación La réplica se conecta al origen con un usuario propio que solo tiene el privilegio de replicación. En `db1`: ```bash sudo mysql ``` Sustituye `your_strong_password` por una contraseña larga y aleatoria: ```sql CREATE USER 'replicador'@'10.0.0.3' IDENTIFIED BY 'your_strong_password' REQUIRE SSL; GRANT REPLICATION SLAVE ON *.* TO 'replicador'@'10.0.0.3'; EXIT; ``` El privilegio conserva el nombre antiguo `REPLICATION SLAVE`. `REQUIRE SSL` obliga a cifrar la conexión; MySQL 8.0 genera certificados autofirmados al instalarse, así que no necesitas crear ninguno. Desde `db2`, comprueba que puedes conectarte con ese usuario: ```bash mysql -h 10.0.0.2 -u replicador -p --ssl-mode=REQUIRED -e "SELECT CURRENT_USER();" ``` ```output +-----------------------+ | CURRENT_USER() | +-----------------------+ | replicador@10.0.0.3 | +-----------------------+ ``` ## Paso 3: Volcar los datos del origen La réplica debe empezar con una copia exacta de los datos del origen. Con GTID, `mysqldump` incluye en el volcado el conjunto de transacciones ya aplicadas, y la réplica continuará justo a partir de ahí. En `db1`, vuelca las bases de datos que quieras replicar (en el ejemplo, `appdb`): ```bash sudo mysqldump --single-transaction --routines --triggers --events \ --set-gtid-purged=ON --databases appdb > appdb.sql ``` `--single-transaction` hace una copia consistente de las tablas InnoDB sin bloquear las escrituras. Para varias bases de datos, enuméralas tras `--databases` separadas por espacios. Es normal que aparezca este aviso: ```output Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. ``` Copia el volcado a la réplica: ```bash scp appdb.sql your_user@10.0.0.3:~/ ``` ## Paso 4: Configurar el servidor réplica En `db2`, edita el mismo archivo: ```bash sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf ``` ```ini [mysqld] server-id = 2 log_bin = /var/log/mysql/mysql-bin.log binlog_expire_logs_seconds = 604800 gtid_mode = ON enforce_gtid_consistency = ON relay_log = /var/log/mysql/mysql-relay-bin.log read_only = ON super_read_only = ON ``` `server-id` debe ser distinto del origen. `read_only` y `super_read_only` impiden escribir en la réplica por error, incluso a usuarios administradores; el proceso de replicación sí puede escribir. La réplica también mantiene su binlog, lo que te permitirá promocionarla a origen si hace falta. Reinicia MySQL: ```bash sudo systemctl restart mysql ``` ## Paso 5: Cargar los datos en la réplica Para importar un volcado con GTID, la réplica no debe tener transacciones propias registradas. Una instalación nueva puede tener alguna (por ejemplo, de `mysql_secure_installation`), así que límpialas. Abre la consola en `db2`: ```bash sudo mysql ``` ```sql SET GLOBAL super_read_only = OFF; RESET MASTER; EXIT; ``` > Advertencia: `RESET MASTER` borra todos los binlogs del servidor en el que se ejecuta. Ejecútalo solo en la réplica, nunca en el origen. Importa el volcado: ```bash sudo mysql < ~/appdb.sql ``` Comprueba que el conjunto de GTID importado coincide con el del origen en el momento del volcado: ```bash sudo mysql -e "SELECT @@GLOBAL.gtid_executed;" ``` ```output +------------------------------------------------+ | @@GLOBAL.gtid_executed | +------------------------------------------------+ | 3e11fa47-71ca-11e1-9e33-c80aa9429562:1-1542 | +------------------------------------------------+ ``` El UUID debe ser el del origen, que puedes consultar en `db1` con `SELECT @@server_uuid;`. ## Paso 6: Iniciar la replicación En `db2`, indica a la réplica dónde está el origen y arranca la replicación: ```bash sudo mysql ``` ```sql CHANGE REPLICATION SOURCE TO SOURCE_HOST = '10.0.0.2', SOURCE_USER = 'replicador', SOURCE_PASSWORD = 'your_strong_password', SOURCE_AUTO_POSITION = 1, SOURCE_SSL = 1; START REPLICA; SET GLOBAL super_read_only = ON; ``` `SOURCE_AUTO_POSITION = 1` hace que la réplica pida al origen las transacciones que le faltan según su `gtid_executed`, sin indicar archivo ni posición. `SOURCE_SSL = 1` cifra la conexión, como exige el usuario creado en el paso 2. Consulta el estado: ```sql SHOW REPLICA STATUS\G ``` Los campos importantes son estos: ```output Replica_IO_State: Waiting for source to send event Source_Host: 10.0.0.2 Replica_IO_Running: Yes Replica_SQL_Running: Yes Last_Error: Seconds_Behind_Source: 0 Source_SSL_Allowed: Yes Auto_Position: 1 ``` `Replica_IO_Running` (descarga de cambios) y `Replica_SQL_Running` (aplicación de cambios) deben estar en `Yes`. `Seconds_Behind_Source` indica el retraso en segundos. ## Paso 7: Probar la replicación En el origen (`db1`), crea una tabla e inserta una fila: ```bash sudo mysql appdb -e "CREATE TABLE prueba_replica (id INT PRIMARY KEY, nota VARCHAR(50)); INSERT INTO prueba_replica VALUES (1, 'hola desde db1');" ``` En la réplica (`db2`), consulta la tabla: ```bash sudo mysql appdb -e "SELECT * FROM prueba_replica;" ``` ```output +----+----------------+ | id | nota | +----+----------------+ | 1 | hola desde db1 | +----+----------------+ ``` Comprueba también que la réplica rechaza escrituras: ```bash sudo mysql appdb -e "INSERT INTO prueba_replica VALUES (2, 'escrito en db2');" ``` ```output ERROR 1290 (HY000) at line 1: The MySQL server is running with the --super-read-only option so it cannot execute this statement ``` Borra la tabla de prueba en el origen; el borrado también se replicará: ```bash sudo mysql appdb -e "DROP TABLE prueba_replica;" ``` Para añadir más réplicas, repite los pasos 3 a 6 en cada una con un `server-id` distinto, un usuario de replicación para su IP y la regla de UFW correspondiente en el origen. ## Paso 8: Promocionar la réplica si el origen falla Si el origen deja de estar disponible, puedes convertir la réplica en el nuevo servidor principal. En `db2`: ```sql STOP REPLICA; RESET REPLICA ALL; SET GLOBAL super_read_only = OFF; SET GLOBAL read_only = OFF; ``` Quita también `read_only` y `super_read_only` de `mysqld.cnf` para que el cambio sobreviva a un reinicio, y apunta tus aplicaciones a `10.0.0.3`. El servidor antiguo no debe volver a recibir escrituras: reconstrúyelo como réplica del nuevo origen siguiendo los pasos 3 a 6. ## Solución de problemas **`Replica_IO_Running: Connecting` con error 2003 o 2005**: la réplica no alcanza el puerto 3306 del origen. Comprueba que `bind-address` en el origen es la IP privada, que MySQL escucha en ella (`sudo ss -tlnp | grep 3306`) y que existe la regla de UFW para la IP de la réplica. **Error 1045 `Access denied for user 'replicador'`**: la contraseña no coincide o el usuario se creó para otra IP. Revisa en el origen con `SELECT user, host FROM mysql.user WHERE user = 'replicador';`. **Error 2061 `Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection`**: falta `SOURCE_SSL = 1` en `CHANGE REPLICATION SOURCE TO`. Ejecuta `STOP REPLICA;`, repite el comando con esa opción y `START REPLICA;`. **Error 1236 `Cannot replicate because the source purged required binary logs`**: la réplica estuvo parada más tiempo que la retención de binlogs. Vuelve a cargarla desde un volcado nuevo (pasos 3 a 6). **`Replica_SQL_Running: No` con error 1062 (clave duplicada)**: alguien escribió directamente en la réplica y los datos divergen. No omitas errores con `replica_skip_errors`: vuelve a cargar la réplica desde un volcado para garantizar que es idéntica al origen. ## Conclusión Tienes una réplica de MySQL 8.0 que recibe los cambios del origen en tiempo real mediante GTID, sobre una conexión cifrada y protegida contra escrituras accidentales. Como siguientes pasos, puedes enviar las consultas de solo lectura de tu aplicación a la réplica, hacer las copias de seguridad desde ella para no cargar el origen y vigilar `Seconds_Behind_Source` con tu sistema de monitorización.