El directorio de datos de MySQL es la carpeta donde el servidor almacena físicamente toda la información: las bases de datos, las tablas, los índices, los logs de transacciones y los archivos de metadatos del sistema. Conocer su estructura interna es esencial para tareas como planificar el almacenamiento, diagnosticar problemas de espacio en disco, realizar backups a nivel de archivos o mover la instalación a otro disco.

Ubicación del directorio de datos

La ubicación del directorio de datos se define mediante la variable datadir. Puedes consultarla desde dentro de MySQL:

SHOW VARIABLES LIKE 'datadir';
Variable_nameValue
datadir/var/lib/mysql/

En la mayoría de las instalaciones en Linux, el directorio por defecto es /var/lib/mysql/. En Windows suele ser C:\ProgramData\MySQL\MySQL Server 8.0\Data\. En macOS con Homebrew, se encuentra en /usr/local/var/mysql/ o /opt/homebrew/var/mysql/.

Desde la terminal, puedes explorar el contenido del directorio:

sudo ls -la /var/lib/mysql/
drwxr-x--- 12 mysql mysql     4096 Mar 18 10:00 .
drwxr-xr-x 42 root  root      4096 Mar 01 08:15 ..
-rw-r-----  1 mysql mysql       56 Feb 15 09:30 auto.cnf
drwxr-x---  2 mysql mysql     4096 Mar 10 14:22 erp_produccion
-rw-r-----  1 mysql mysql 12582912 Mar 18 09:58 ibdata1
-rw-r-----  1 mysql mysql 50331648 Mar 18 10:00 ib_logfile0
-rw-r-----  1 mysql mysql 50331648 Mar 17 22:00 ib_logfile1
drwxr-x---  2 mysql mysql    12288 Mar 15 11:30 mysql
drwxr-x---  2 mysql mysql     4096 Feb 15 09:30 performance_schema
drwxr-x---  2 mysql mysql     4096 Feb 15 09:30 sys
drwxr-x---  2 mysql mysql     8192 Mar 18 09:45 tienda_online

Observa que todo pertenece al usuario y grupo mysql. Esto es crítico para la seguridad: solo el proceso de MySQL debe tener acceso a estos archivos.

Estructura interna

Cada componente del directorio de datos cumple una función específica.

Directorios de bases de datos

Cada base de datos que creas en MySQL se convierte en un subdirectorio dentro del directorio de datos. Si ejecutas CREATE DATABASE tienda_online, se creará la carpeta /var/lib/mysql/tienda_online/.

sudo ls -la /var/lib/mysql/tienda_online/
-rw-r----- 1 mysql mysql  8694 Mar 18 09:30 productos.ibd
-rw-r----- 1 mysql mysql  4096 Mar 15 14:00 categorias.ibd
-rw-r----- 1 mysql mysql 16384 Mar 18 09:45 pedidos.ibd
-rw-r----- 1 mysql mysql  8192 Mar 17 10:20 clientes.ibd

Con la opción innodb_file_per_table habilitada (que es el valor por defecto desde MySQL 5.6), cada tabla InnoDB tiene su propio archivo .ibd que contiene tanto los datos como los índices. Este enfoque facilita la gestión del espacio, ya que puedes ver exactamente cuánto ocupa cada tabla.

El archivo ibdata1

El archivo ibdata1 es el tablespace compartido del sistema de InnoDB. Almacena los metadatos internos de InnoDB, el diccionario de datos (en versiones anteriores a MySQL 8.0), los datos de las tablas de undo y el change buffer.

SHOW VARIABLES LIKE 'innodb_data_file_path';
Variable_nameValue
innodb_data_file_pathibdata1:12M:autoextend

La configuración 12M:autoextend indica que el archivo comienza con 12 MB y crece automáticamente según sea necesario. Un problema clásico es que ibdata1 crece y nunca se reduce, incluso después de eliminar tablas grandes. Por eso, tener innodb_file_per_table = ON es tan importante: los datos de las tablas se almacenan en archivos individuales que se pueden eliminar limpiamente.

Redo logs (logs de transacciones)

Los archivos ib_logfile0 e ib_logfile1 (o, en MySQL 8.0.30+, los archivos dentro de #innodb_redo/) son los redo logs de InnoDB. Registran cada cambio antes de que se aplique a los archivos de datos, garantizando la durabilidad de las transacciones.

Si el servidor se apaga inesperadamente, InnoDB usa estos logs para reconstruir las transacciones completadas que aún no se habían escrito a los archivos de datos. Es el mecanismo central de la recuperación ante fallos.

SHOW VARIABLES LIKE 'innodb_log_file_size';
Variable_nameValue
innodb_log_file_size50331648

Ese valor (48 MB por defecto) puede ser insuficiente para servidores con muchas escrituras. En producción, valores de 256 MB a 1 GB son habituales.

Undo tablespaces

Los undo tablespaces almacenan las versiones anteriores de los registros modificados, lo que permite que otras transacciones lean datos consistentes mientras una transacción está en curso (MVCC). En MySQL 8.0, se almacenan en archivos separados:

sudo ls -la /var/lib/mysql/undo_*
-rw-r----- 1 mysql mysql 16777216 Mar 18 09:58 /var/lib/mysql/undo_001
-rw-r----- 1 mysql mysql 16777216 Mar 18 09:58 /var/lib/mysql/undo_002

Binary logs

Si la replicación o la recuperación punto en el tiempo están habilitadas, verás archivos de binary log:

sudo ls -la /var/lib/mysql/binlog.*
-rw-r----- 1 mysql mysql 1073742 Mar 18 09:30 binlog.000047
-rw-r----- 1 mysql mysql  524288 Mar 18 10:00 binlog.000048
-rw-r----- 1 mysql mysql      78 Mar 18 09:30 binlog.index

El archivo binlog.index lista todos los binary logs activos. Estos archivos registran cada modificación de datos y son esenciales tanto para la replicación maestro-replica como para restaurar datos hasta un punto específico en el tiempo.

Caso práctico: analizar el uso de espacio por tabla

Para planificar el almacenamiento, necesitas saber cuánto espacio ocupa cada tabla. La consulta más útil es:

SELECT
  TABLE_SCHEMA AS base_datos,
  TABLE_NAME AS tabla,
  ROUND(DATA_LENGTH / 1024 / 1024, 2) AS datos_mb,
  ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS indices_mb,
  ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS total_mb,
  TABLE_ROWS AS filas_aprox
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'erp_produccion'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC
LIMIT 10;
base_datostabladatos_mbindices_mbtotal_mbfilas_aprox
erp_produccionfact_ventas2840.001230.004070.0018432500
erp_produccionlog_actividad1580.00420.002000.009841200
erp_producciondetalle_pedidos890.00340.001230.005200000
erp_produccionproductos45.0012.0057.00128500
erp_produccionclientes22.008.0030.0085200

Para ver el espacio total de todas las bases de datos:

SELECT
  TABLE_SCHEMA AS base_datos,
  ROUND(SUM(DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024 / 1024, 2) AS total_gb,
  COUNT(*) AS num_tablas
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN
  ('information_schema', 'performance_schema', 'mysql', 'sys')
GROUP BY TABLE_SCHEMA
ORDER BY total_gb DESC;
base_datostotal_gbnum_tablas
erp_produccion7.8294
tienda_online2.1538
analytics1.4322

Caso práctico: mover el directorio de datos a otro disco

Cuando el disco donde reside el directorio de datos se queda sin espacio, necesitas moverlo a un disco más grande. Este es un procedimiento delicado que requiere detener el servidor.

# 1. Detener MySQL
sudo systemctl stop mysql
 
# 2. Copiar el directorio de datos al nuevo disco
sudo rsync -av /var/lib/mysql/ /data/mysql/
 
# 3. Verificar que los permisos son correctos
sudo chown -R mysql:mysql /data/mysql
sudo chmod 750 /data/mysql

Luego, editar el archivo de configuración:

[mysqld]
datadir = /data/mysql

Si tu sistema usa AppArmor (Ubuntu), necesitas actualizar el perfil:

sudo nano /etc/apparmor.d/usr.sbin.mysqld
# Cambiar /var/lib/mysql/ por /data/mysql/
sudo systemctl restart apparmor

Si usa SELinux (CentOS/RHEL):

sudo semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
sudo restorecon -Rv /data/mysql

Finalmente, inicia MySQL y verifica:

sudo systemctl start mysql
mysql -u root -p -e "SHOW VARIABLES LIKE 'datadir';"
Variable_nameValue
datadir/data/mysql/

Es una buena práctica mantener el directorio de datos original durante unos días como respaldo, hasta confirmar que todo funciona correctamente en la nueva ubicación. Solo después de esa verificación, elimina el directorio antiguo para liberar espacio.

Conocer la estructura del directorio de datos te da control sobre el almacenamiento físico de MySQL. En el siguiente artículo veremos cómo personalizar el prompt del cliente MySQL para trabajar de forma más cómoda y eficiente.

Escrito por Eduardo Lázaro