Tutorial completo de MySQL 8: instalación, administración, tipos de datos y backup (2026)

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

INT / BIGINT

Números enteros

Usa UNSIGNED para IDs y cantidades positivas

DECIMAL(p, s)

Precios, importes

Exacto. Nunca uses FLOAT para dinero

VARCHAR(n)

Texto corto variable

Almacena solo los bytes usados

TEXT

Texto largo

No se puede indexar completo

TINYINT(1)

Booleanos

0 = false, 1 = true

DATE

Solo fecha

Formato: YYYY-MM-DD

DATETIME

Fecha y hora

Formato: YYYY-MM-DD HH:MM:SS

TIMESTAMP

Marca de tiempo

Se convierte a UTC internamente

JSON

Datos semiestructurados

Validado y optimizado en MySQL 5.7+

ENUM

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, no utf8: el utf8 de MySQL es en realidad UTF-8 de 3 bytes, sin soporte para emojis ni algunos caracteres CJK. utf8mb4 es 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 EXPLAIN antes 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

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP