Artículo original de enero de 2003. Reescrito completamente en mayo de 2026 por David Carrero. El original cubría MySQL 3.x desde la línea de comandos. Esta versión cubre MySQL 8 con instalación, configuración, gestión de usuarios, backup/restore y buenas prácticas para entornos de producción.
MySQL en 2026: por qué sigue siendo la primera opción
MySQL tiene más de 30 años y todavía encabeza los rankings de uso. DB-Engines lo sitúa como el segundo motor de bases de datos más popular del mundo (solo por detrás de Oracle, que es de pago). La mayoría de hostings compartidos lo incluyen por defecto, WordPress lo requiere, y gigantes como Facebook, Twitter y YouTube lo usan o han usado en producción con miles de millones de registros.
La versión actual es MySQL 8.4 (LTS). Respecto a las versiones de la era 2003 que cubría el artículo original, los cambios son enormes: soporte nativo para JSON, window functions, CTEs (Common Table Expressions), roles de usuario, mejoras de rendimiento sustanciales y un optimizador de consultas completamente reescrito.
Instalación de MySQL 8
Ubuntu 24.04 / Debian 12
sudo apt update sudo apt install -y mysql-server # Comprobar que está en marcha sudo systemctl status mysql # Configuración inicial de seguridad (muy recomendada en producción) sudo mysql_secure_installation
El script mysql_secure_installation te pregunta si quieres establecer una contraseña para root, eliminar usuarios anónimos, deshabilitar el acceso remoto de root y borrar la base de datos de test. En producción responde «sí» a todo.
Red Hat / AlmaLinux / Rocky Linux
sudo dnf install -y mysql-server sudo systemctl enable --now mysqld sudo mysql_secure_installation
Docker (para desarrollo local)
docker run -d --name mysql8 -e MYSQL_ROOT_PASSWORD=secreto -e MYSQL_DATABASE=miapp -e MYSQL_USER=appuser -e MYSQL_PASSWORD=apppass -p 3306:3306 mysql:8.4
El cliente de línea de comandos
El cliente mysql es la herramienta más directa para administrar el servidor. Conecta así:
# Conectar como root en local sudo mysql -u root -p # Conectar a un host remoto con usuario específico mysql -h 192.168.1.10 -u appuser -p miapp # Ejecutar un script SQL directamente mysql -u root -p miapp < script.sql # Ejecutar una consulta puntual sin entrar en el cliente mysql -u root -p -e "SHOW DATABASES;"
Dentro del cliente, los comandos que más vas a usar:
SHOW DATABASES; -- Ver todas las bases de datos USE nombre_base; -- Seleccionar una base de datos SHOW TABLES; -- Ver las tablas de la base activa DESCRIBE nombre_tabla; -- Ver la estructura de una tabla SHOW CREATE TABLE nombre_tablaG -- Ver el CREATE TABLE completo SHOW PROCESSLIST; -- Ver conexiones activas SHOW STATUS LIKE 'Threads%'; -- Estado del servidor exit -- Salir del cliente
Gestión de bases de datos y tablas
-- Crear una base de datos con codificación correcta para español
CREATE DATABASE IF NOT EXISTS tienda
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE tienda;
-- Crear una tabla completa con los tipos más comunes
CREATE TABLE productos (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(50) NOT NULL UNIQUE,
nombre VARCHAR(150) NOT NULL,
descripcion TEXT,
precio DECIMAL(10, 2) UNSIGNED NOT NULL,
stock INT NOT NULL DEFAULT 0,
peso_kg FLOAT,
activo TINYINT(1) NOT NULL DEFAULT 1,
fecha_alta DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
fecha_mod DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_sku (sku),
INDEX idx_activo_precio (activo, precio)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Modificar una tabla existente
ALTER TABLE productos
ADD COLUMN id_categoria INT UNSIGNED AFTER id,
ADD COLUMN imagen_url VARCHAR(255) AFTER descripcion;
Qué motor usar: InnoDB siempre, a menos que tengas un caso muy específico. InnoDB soporta transacciones, claves foráneas y tiene mejor rendimiento en escrituras concurrentes. MyISAM (el motor antiguo) solo tiene sentido para tablas de solo lectura con búsqueda de texto completo en versiones viejas de MySQL.
Tipos de datos más usados en MySQL 8
Tipo |
Uso |
Notas |
| Números enteros | Usa |
| Precios, importes | Exacto. Nunca uses FLOAT para dinero |
| Texto corto variable | Almacena solo los bytes usados |
| Texto largo | No se puede indexar completo |
| Booleanos | 0 = false, 1 = true |
| Solo fecha | Formato: YYYY-MM-DD |
| Fecha y hora | Formato: YYYY-MM-DD HH:MM:SS |
| Marca de tiempo | Se convierte a UTC internamente |
| Datos semiestructurados | Validado y optimizado en MySQL 5.7+ |
| Lista cerrada de valores | Eficiente pero rígido: piénsalo antes de usarlo |
Gestión de usuarios y permisos
Una de las primeras cosas que debes hacer en un servidor MySQL de producción es no usar el usuario root desde las aplicaciones. Crea usuarios específicos con los permisos mínimos que necesitan:
-- Ver usuarios existentes SELECT user, host FROM mysql.user; -- Crear un usuario para la aplicación web (solo puede conectar desde localhost) CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'contraseña_segura_aqui'; -- Dar solo los permisos que necesita (no GRANT ALL en producción) GRANT SELECT, INSERT, UPDATE, DELETE ON tienda.* TO 'appuser'@'localhost'; -- Para migraciones o scripts de mantenimiento, un usuario con más privilegios CREATE USER 'adminapp'@'localhost' IDENTIFIED BY 'otra_contraseña'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP ON tienda.* TO 'adminapp'@'localhost'; -- Aplicar los cambios de permisos FLUSH PRIVILEGES; -- Ver los permisos de un usuario SHOW GRANTS FOR 'appuser'@'localhost'; -- Eliminar un usuario DROP USER 'appuser'@'localhost'; -- Cambiar la contraseña de un usuario ALTER USER 'appuser'@'localhost' IDENTIFIED BY 'nueva_contraseña';
Backup y restauración
El backup más usado en MySQL es mysqldump, que genera un fichero SQL con el esquema y los datos. Es simple, funciona en cualquier versión y el resultado es texto legible:
# Backup de una base de datos mysqldump -u root -p tienda > backup_tienda_$(date +%Y%m%d).sql # Backup de todas las bases de datos mysqldump -u root -p --all-databases > backup_completo_$(date +%Y%m%d).sql # Backup comprimido (para bases de datos grandes) mysqldump -u root -p tienda | gzip > backup_tienda_$(date +%Y%m%d).sql.gz # Restaurar un backup mysql -u root -p tienda < backup_tienda_20260509.sql # Restaurar un backup comprimido gunzip < backup_tienda_20260509.sql.gz | mysql -u root -p tienda
Para bases de datos grandes en producción (varios GB), mysqldump bloquea las tablas y puede ser lento. En esos casos se usa Percona XtraBackup, que hace copias en caliente sin interrumpir el servicio.
Variables de configuración importantes
El fichero de configuración es /etc/mysql/mysql.conf.d/mysqld.cnf en Ubuntu o /etc/my.cnf en Red Hat. Los parámetros que más afectan al rendimiento:
[mysqld] # Buffer pool de InnoDB: regla general, 70-80% de la RAM disponible innodb_buffer_pool_size = 1G # Tamaño del log de transacciones (más grande = escrituras más rápidas) innodb_log_file_size = 256M # Máximo de conexiones simultáneas max_connections = 150 # Zona horaria (importante para TIMESTAMP y funciones de fecha) default_time_zone = 'Europe/Madrid' # Codificación por defecto character_set_server = utf8mb4 collation_server = utf8mb4_unicode_ci # Modo estricto: rechaza datos inválidos en vez de corregirlos silenciosamente sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
Después de cambiar el fichero, reinicia el servicio: sudo systemctl restart mysql.
Monitorización básica
-- Ver el estado general del servidor
SHOW STATUS;
-- Las consultas más lentas (requiere slow query log activado)
SHOW VARIABLES LIKE 'slow_query%';
-- Activar el log de consultas lentas (umbral: 1 segundo)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
-- Ver conexiones activas y qué están ejecutando
SHOW PROCESSLIST;
-- Tamaño de cada base de datos en disco
SELECT
table_schema AS base_de_datos,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS tamanio_mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY tamanio_mb DESC;
-- Tamaño de cada tabla
SELECT
table_name AS tabla,
table_rows AS filas_aprox,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS tamanio_mb
FROM information_schema.tables
WHERE table_schema = 'tienda'
ORDER BY (data_length + index_length) DESC;
Buenas prácticas que no aparecen en los tutoriales básicos
- Usa
utf8mb4, noutf8: elutf8de MySQL es en realidad UTF-8 de 3 bytes, sin soporte para emojis ni algunos caracteres CJK.utf8mb4es el UTF-8 real. - Siempre claves foráneas en InnoDB: garantizan integridad referencial. Sin ellas puedes tener pedidos sin cliente o líneas de pedido sin pedido padre.
- Nunca hagas
SELECT *en producción: trae columnas innecesarias, ocupa más ancho de banda y dificulta el uso de índices de cobertura. - Activa el modo estricto (
STRICT_TRANS_TABLES): por defecto MySQL acepta datos inválidos y los corrige silenciosamente. Con el modo estricto falla con un error claro, lo que es mucho mejor que datos corruptos silenciosos. - Usa
EXPLAINantes de poner en producción consultas sobre tablas grandes:EXPLAIN SELECT ...muestra si MySQL usa índices o hace full table scan. - Backups automáticos y verificados: un backup que no se puede restaurar no es un backup. Prueba la restauración al menos una vez al mes en un entorno de pruebas.
Para aprender a escribir consultas avanzadas sobre estas bases, consulta el Curso completo de SQL con ejemplos de JOINs, subconsultas, transacciones e índices. Si necesitas integrar MySQL en una aplicación PHP, el artículo Cómo interactuar con MySQL usando PHP 8 y PDO cubre la conexión con PDO y sentencias preparadas.
Imagen: Pexels / panumas nikhomkhai
