--- title: "Cómo configurar ProxySQL con MySQL en Ubuntu 24.04" description: "Instala ProxySQL en Ubuntu 24.04 y reparte la carga de MySQL: escrituras al primario, lecturas a las réplicas y detección automática de roles con read_only." category: "Base de Datos Avanzada" language: es source: https://cubepath.com/es/docs/base-de-datos-avanzada/proxysql-para-equilibrio-de-carga-de-mysql updated: 2026-09-25 --- # Cómo configurar ProxySQL con MySQL en Ubuntu 24.04 ProxySQL es un proxy para MySQL que entiende el protocolo y las consultas: mantiene un pool de conexiones hacia los servidores, enruta cada consulta según reglas y detecta qué servidor es el primario y cuáles son réplicas. En este tutorial instalarás ProxySQL en Ubuntu 24.04 delante de un primario MySQL con dos réplicas, enviarás las escrituras al primario y las lecturas a las réplicas, y verificarás el enrutamiento con las tablas de estadísticas de ProxySQL, todo sin cambiar el código de la aplicación. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS para ProxySQL, por ejemplo un VPS de CubePath. Puede ser el mismo servidor de la aplicación. - Replicación MySQL funcionando con un primario y al menos una réplica, con `read_only = ON` en las réplicas. En esta guía se usan estas direcciones privadas: | Rol | IP privada | |-----|------------| | Primario | `10.0.0.21` | | Réplica 1 | `10.0.0.22` | | Réplica 2 | `10.0.0.23` | - El puerto 3306 de los servidores MySQL accesible desde el servidor de ProxySQL. - Un usuario no root con privilegios `sudo`. ## Paso 1: Crear los usuarios en MySQL ProxySQL necesita dos usuarios en MySQL: uno de monitorización, con el que comprueba cada pocos segundos si un servidor responde y si tiene `read_only` activo, y el usuario de la aplicación. Créalos en el **primario**; la replicación los copiará a las réplicas: ```bash sudo mysql ``` ```sql CREATE USER 'monitor'@'10.0.0.%' IDENTIFIED WITH mysql_native_password BY 'your_monitor_password'; GRANT USAGE, REPLICATION CLIENT ON *.* TO 'monitor'@'10.0.0.%'; CREATE DATABASE IF NOT EXISTS appdb; CREATE USER 'appuser'@'10.0.0.%' IDENTIFIED WITH mysql_native_password BY 'your_app_password'; GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'10.0.0.%'; EXIT; ``` Sustituye las contraseñas por valores propios. Se usa `mysql_native_password` porque es el método de autenticación con el que ProxySQL tiene mejor compatibilidad hacia los servidores. Está disponible en MySQL 8.0, la versión de Ubuntu 24.04; en MySQL 8.4 y posteriores viene desactivado y tendrías que habilitarlo o usar `caching_sha2_password` con TLS. ## Paso 2: Instalar ProxySQL desde el repositorio oficial Descarga la clave del repositorio de ProxySQL para la rama 2.7.x: ```bash sudo apt update sudo apt install curl lsb-release mysql-client sudo curl -fsSL -o /etc/apt/keyrings/proxysql.asc https://repo.proxysql.com/ProxySQL/proxysql-2.7.x/repo_pub_key ``` Añade el repositorio: ```bash echo "deb [signed-by=/etc/apt/keyrings/proxysql.asc] https://repo.proxysql.com/ProxySQL/proxysql-2.7.x/$(lsb_release -sc)/ ./" | sudo tee /etc/apt/sources.list.d/proxysql.list ``` Instala ProxySQL y arranca el servicio: ```bash sudo apt update sudo apt install proxysql sudo systemctl enable --now proxysql ``` Comprueba que está escuchando. El puerto 6032 es la interfaz de administración y el 6033 el que usarán las aplicaciones: ```bash sudo ss -ltnp | grep proxysql ``` ```output LISTEN 0 1024 0.0.0.0:6032 0.0.0.0:* users:(("proxysql",pid=2211,fd=31)) LISTEN 0 1024 0.0.0.0:6033 0.0.0.0:* users:(("proxysql",pid=2211,fd=26)) ``` ## Paso 3: Entender cómo guarda ProxySQL la configuración ProxySQL no se configura editando un archivo. `/etc/proxysql.cnf` solo se lee la primera vez que arranca; a partir de entonces la configuración vive en una base de datos SQLite en `/var/lib/proxysql` y se modifica con SQL desde la interfaz de administración. Hay tres capas: - **MEMORY**: donde editas con `INSERT` y `UPDATE`. Los cambios aún no tienen efecto. - **RUNTIME**: la configuración activa. Pasas a ella con `LOAD ... TO RUNTIME`. - **DISK**: la persistencia. Guardas con `SAVE ... TO DISK` para que sobreviva a un reinicio. Por eso, en los pasos siguientes cada bloque termina con un `LOAD` y un `SAVE`. ## Paso 4: Cambiar la contraseña de administración Conéctate a la interfaz de administración con las credenciales por defecto, `admin`/`admin`, que solo se aceptan desde localhost: ```bash mysql -u admin -padmin -h 127.0.0.1 -P 6032 --prompt='ProxySQLAdmin> ' ``` Cámbialas de inmediato: ```sql UPDATE global_variables SET variable_value = 'admin:your_admin_password' WHERE variable_name = 'admin-admin_credentials'; LOAD ADMIN VARIABLES TO RUNTIME; SAVE ADMIN VARIABLES TO DISK; ``` A partir de ahora conéctate con `-padmin` sustituido por tu nueva contraseña. Mantén el puerto 6032 cerrado al exterior en el firewall. ## Paso 5: Registrar los servidores y los hostgroups ProxySQL agrupa los servidores en hostgroups. Usarás el hostgroup 10 para escrituras y el 20 para lecturas. Configura primero el usuario de monitorización: ```sql UPDATE global_variables SET variable_value = 'monitor' WHERE variable_name = 'mysql-monitor_username'; UPDATE global_variables SET variable_value = 'your_monitor_password' WHERE variable_name = 'mysql-monitor_password'; LOAD MYSQL VARIABLES TO RUNTIME; SAVE MYSQL VARIABLES TO DISK; ``` Indica a ProxySQL qué pareja de hostgroups forma una replicación. Con esta tabla, ProxySQL mira `read_only` en cada servidor y lo coloca automáticamente en el hostgroup 10 si es `OFF` o en el 20 si es `ON`: ```sql INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment) VALUES (10, 20, 'cluster app'); ``` Añade los tres servidores. Basta con ponerlos todos en el hostgroup de lectura: el monitor moverá el primario al de escritura: ```sql INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (20, '10.0.0.21', 3306); INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (20, '10.0.0.22', 3306); INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (20, '10.0.0.23', 3306); LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK; ``` Espera unos segundos y comprueba cómo han quedado: ```sql SELECT hostgroup_id, hostname, status FROM runtime_mysql_servers ORDER BY hostgroup_id, hostname; ``` ```output +--------------+-----------+--------+ | hostgroup_id | hostname | status | +--------------+-----------+--------+ | 10 | 10.0.0.21 | ONLINE | | 20 | 10.0.0.21 | ONLINE | | 20 | 10.0.0.22 | ONLINE | | 20 | 10.0.0.23 | ONLINE | +--------------+-----------+--------+ ``` El primario aparece en ambos hostgroups porque, por defecto, el escritor también atiende lecturas (variable `mysql-monitor_writer_is_also_reader`). Si quieres que las lecturas vayan solo a las réplicas, pon esa variable a `false` y vuelve a cargar las variables y los servidores. Verifica también que el monitor puede leer `read_only` sin errores: ```sql SELECT hostname, read_only, error FROM monitor.mysql_server_read_only_log ORDER BY time_start_us DESC LIMIT 3; ``` ```output +-----------+-----------+-------+ | hostname | read_only | error | +-----------+-----------+-------+ | 10.0.0.23 | 1 | NULL | | 10.0.0.22 | 1 | NULL | | 10.0.0.21 | 0 | NULL | +-----------+-----------+-------+ ``` Si la columna `error` muestra `Access denied`, revisa el usuario y la contraseña de monitorización. ## Paso 6: Añadir el usuario de la aplicación Las aplicaciones se autentican contra ProxySQL, que luego se conecta a MySQL con las mismas credenciales. Registra el usuario con el hostgroup de escritura como destino por defecto, de modo que toda consulta que no coincida con una regla vaya al primario: ```sql INSERT INTO mysql_users (username, password, default_hostgroup) VALUES ('appuser', 'your_app_password', 10); LOAD MYSQL USERS TO RUNTIME; SAVE MYSQL USERS TO DISK; ``` La contraseña debe ser la misma que definiste en MySQL en el paso 1. ## Paso 7: Separar lecturas y escrituras con reglas de consulta Las reglas se evalúan en orden de `rule_id`. La primera envía los `SELECT ... FOR UPDATE` al primario, porque bloquean filas y deben ir dentro de la transacción de escritura. La segunda envía el resto de `SELECT` a las réplicas: ```sql INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) VALUES (1, 1, '^SELECT.*FOR UPDATE', 10, 1); INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) VALUES (2, 1, '^SELECT', 20, 1); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK; ``` `INSERT`, `UPDATE`, `DELETE` y cualquier otra sentencia no coinciden con ninguna regla y van al `default_hostgroup` del usuario, el 10. Dentro de una transacción explícita, ProxySQL mantiene todas las consultas en el mismo servidor (`transaction_persistent` está activado por defecto en `mysql_users`), así que un `SELECT` después de un `UPDATE` en la misma transacción no se escapa a una réplica. Sal de la interfaz de administración con `EXIT`. ## Paso 8: Probar el enrutamiento Conéctate como lo haría la aplicación, al puerto 6033. Ejecuta varias veces una lectura que devuelva el nombre del servidor: ```bash for i in 1 2 3 4; do mysql -u appuser -p'your_app_password' -h 127.0.0.1 -P 6033 -N -e "SELECT @@hostname;"; done ``` ```output mysql-replica-2 mysql-replica-1 mysql-primary mysql-replica-2 ``` Las lecturas se reparten entre los servidores del hostgroup 20. Ahora haz una escritura: ```bash mysql -u appuser -p'your_app_password' -h 127.0.0.1 -P 6033 appdb -e "CREATE TABLE IF NOT EXISTS t (id INT PRIMARY KEY); INSERT INTO t VALUES (1);" ``` Vuelve a la interfaz de administración y consulta las estadísticas por patrón de consulta: ```sql SELECT hostgroup, digest_text, count_star FROM stats_mysql_query_digest ORDER BY count_star DESC LIMIT 5; ``` ```output +-----------+---------------------------------------------------+------------+ | hostgroup | digest_text | count_star | +-----------+---------------------------------------------------+------------+ | 20 | SELECT @@hostname | 4 | | 10 | CREATE TABLE IF NOT EXISTS t (id INT PRIMARY KEY) | 1 | | 10 | INSERT INTO t VALUES (?) | 1 | +-----------+---------------------------------------------------+------------+ ``` El `SELECT` fue al hostgroup 20 y las escrituras al 10. Esta tabla es también la herramienta para encontrar las consultas más frecuentes y lentas de tu aplicación. ## Paso 9: Ajustar el reparto de carga y el retraso de réplica El peso (`weight`) de cada servidor controla la proporción de tráfico que recibe dentro de su hostgroup, y `max_replication_lag` saca temporalmente de rotación a una réplica que va demasiado retrasada. Por ejemplo, para enviar el doble de lecturas a la réplica 1 y apartar cualquier réplica con más de 10 segundos de retraso: ```sql UPDATE mysql_servers SET weight = 2000 WHERE hostname = '10.0.0.22' AND hostgroup_id = 20; UPDATE mysql_servers SET max_replication_lag = 10 WHERE hostgroup_id = 20; LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK; ``` El peso por defecto es 1000. Una réplica apartada por retraso aparece con estado `SHUNNED` en `runtime_mysql_servers` y vuelve a `ONLINE` cuando se pone al día. Puedes ver cómo se reparten las conexiones y consultas por servidor en `stats_mysql_connection_pool`: ```sql SELECT hostgroup, srv_host, status, ConnUsed, ConnFree, Queries FROM stats_mysql_connection_pool; ``` ## Solución de problemas - **Todos los servidores quedan en el hostgroup 20**: el primario tiene `read_only = ON` o el monitor no puede conectarse. Revisa `monitor.mysql_server_read_only_log` y `monitor.mysql_server_connect_log`. - **`Access denied` al conectar por el puerto 6033**: el usuario no existe en `mysql_users`, falta `LOAD MYSQL USERS TO RUNTIME` o la contraseña no coincide con la de MySQL. - **Los cambios desaparecen al reiniciar**: faltó el `SAVE ... TO DISK` correspondiente. - **Editaste `/etc/proxysql.cnf` y no pasa nada**: es lo esperado, ese archivo solo se usa si no existe la base de datos en `/var/lib/proxysql`. Haz los cambios desde la interfaz de administración. - **Lecturas que no ven datos recién escritos**: es el retraso de replicación. Envía esas lecturas concretas al primario con una regla más específica o dentro de una transacción. ## Conclusión Tienes ProxySQL en Ubuntu 24.04 separando lecturas y escrituras entre un primario y dos réplicas MySQL, detectando los roles por `read_only` y apartando réplicas retrasadas, con estadísticas para verificar a dónde va cada consulta. Como siguientes pasos, puedes montar un segundo ProxySQL y sincronizarlos con ProxySQL Cluster, activar la caché de consultas con `cache_ttl` en reglas concretas y exportar las métricas al sistema de monitorización que ya uses.