Gestión de Usuarios y Permisos en MySQL/MariaDB: Guía Completa de Seguridad
Introducción
La gestión efectiva de usuarios y permisos es la piedra angular de la seguridad de bases de datos en MySQL y MariaDB. Un control de acceso adecuado garantiza que los usuarios solo puedan realizar operaciones autorizadas en bases de datos y tablas específicas, protegiendo datos sensibles de accesos no autorizados, modificaciones o eliminaciones. En una era donde las brechas de datos son cada vez más comunes y costosas, implementar una gestión robusta de usuarios y permisos no es solo una buena práctica—es una necesidad.
MySQL y MariaDB proporcionan un sistema de privilegios sofisticado que opera en múltiples niveles, desde privilegios globales del servidor hasta permisos individuales por columna. Este control granular permite a los administradores de bases de datos implementar el principio de menor privilegio, donde cada usuario recibe solo los permisos mínimos necesarios para realizar sus funciones. Comprender este sistema es esencial para cualquier persona responsable de la seguridad y administración de bases de datos.
Esta guía completa explora todos los aspectos de la gestión de usuarios y permisos en MySQL/MariaDB, desde la creación de usuarios y asignación de privilegios básicos hasta la implementación de características de seguridad avanzadas como control de acceso basado en roles, auditoría de actividades de usuarios y solución de problemas de permisos. Ya sea que esté configurando un nuevo servidor de base de datos o auditando una instalación existente, esta guía proporciona el conocimiento y ejemplos prácticos necesarios para implementar un control de acceso seguro y mantenible.
Prerrequisitos
Antes de sumergirse en la gestión de usuarios y permisos, asegúrese de tener:
Requisitos del Sistema
- MySQL 5.7+, MySQL 8.0+ o MariaDB 10.3+ instalado
- Acceso a un servidor Linux (Ubuntu 20.04+, CentOS 7+ o Debian 10+)
- Acceso root o administrativo a MySQL/MariaDB
- Acceso sudo o root al sistema operativo
Acceso a MySQL
- Capacidad para conectarse como usuario root de MySQL
- Conocimiento de la contraseña de root
- Herramientas cliente de MySQL instaladas
Requisitos de Conocimiento
- Sintaxis básica de consultas SQL
- Comprensión de conceptos de bases de datos (bases de datos, tablas, usuarios)
- Fundamentos de línea de comandos de Linux
- Conceptos básicos de redes para acceso remoto
Herramientas Recomendadas
- MySQL Workbench o herramienta GUI similar (opcional)
- Emulador de terminal para acceso por línea de comandos
- Editor de texto para archivos de configuración
Comprendiendo el Sistema de Privilegios de MySQL
Niveles de Privilegios
MySQL/MariaDB implementa un sistema de privilegios jerárquico con cinco niveles distintos:
1. Privilegios Globales: Se aplican a todas las bases de datos en el servidor
- Almacenados en la tabla
mysql.user - Ejemplos: CREATE USER, SUPER, RELOAD
2. Privilegios de Base de Datos: Se aplican a todos los objetos dentro de una base de datos específica
- Almacenados en la tabla
mysql.db - Ejemplos: CREATE, DROP, GRANT OPTION en una base de datos
3. Privilegios de Tabla: Se aplican a todas las columnas en una tabla específica
- Almacenados en la tabla
mysql.tables_priv - Ejemplos: SELECT, INSERT, UPDATE, DELETE en una tabla
4. Privilegios de Columna: Se aplican a columnas específicas en una tabla
- Almacenados en la tabla
mysql.columns_priv - Ejemplos: SELECT o UPDATE en columnas específicas
5. Privilegios de Rutina: Se aplican a procedimientos almacenados y funciones
- Almacenados en la tabla
mysql.procs_priv - Ejemplos: EXECUTE, ALTER ROUTINE
Tipos Comunes de Privilegios
Manipulación de Datos:
SELECT: Leer datos de tablasINSERT: Agregar nuevas filas a tablasUPDATE: Modificar datos existentesDELETE: Eliminar filas de tablas
Estructura de Base de Datos:
CREATE: Crear bases de datos y tablasALTER: Modificar estructuras de tablasDROP: Eliminar bases de datos y tablasINDEX: Crear o eliminar índices
Administrativos:
GRANT OPTION: Otorgar privilegios a otros usuariosSUPER: Operaciones administrativasRELOAD: Recargar tablas de permisos, flush privilegesSHUTDOWN: Apagar el servidor MySQLPROCESS: Ver todos los procesosREPLICATION SLAVE: Para esclavos de replicaciónREPLICATION CLIENT: Consultar estado de replicación
Especiales:
ALL PRIVILEGES: Todos los privilegios disponibles (excepto GRANT OPTION)USAGE: Sinónimo de "sin privilegios" (solo inicio de sesión)
Métodos de Autenticación
mysql_native_password: Autenticación tradicional de MySQL (predeterminado en MySQL 5.7)
caching_sha2_password: Más seguro, predeterminado en MySQL 8.0+
auth_socket: Usa credenciales del sistema operativo (Linux)
Autenticación PAM: Integración con PAM del sistema (MariaDB)
Gestión de Usuarios Paso a Paso
Paso 1: Conectarse a MySQL como Root
Conéctese a MySQL con privilegios administrativos:
mysql -u root -p
O usando autenticación sudo:
sudo mysql
Verifique su conexión actual:
SELECT USER(), CURRENT_USER(), DATABASE();
Paso 2: Ver Usuarios Existentes
Liste todos los usuarios en el sistema:
-- Ver todos los usuarios
SELECT User, Host FROM mysql.user;
-- Ver usuarios con más detalles
SELECT User, Host, account_locked, password_expired
FROM mysql.user
ORDER BY User, Host;
-- Verificar métodos de autenticación
SELECT User, Host, plugin
FROM mysql.user
WHERE User != '';
Paso 3: Crear Usuarios Básicos
Cree usuarios con diferentes métodos de autenticación:
-- Crear usuario con contraseña (estilo MySQL 5.7)
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
-- Crear usuario con plugin de autenticación específico (MySQL 8.0+)
CREATE USER 'app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'SecurePassword123!';
-- Crear usuario accesible desde cualquier host
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'SecurePassword123!';
-- Crear usuario desde dirección IP específica
CREATE USER 'admin_user'@'192.168.1.100' IDENTIFIED BY 'SecurePassword123!';
-- Crear usuario desde rango IP
CREATE USER 'network_user'@'192.168.1.%' IDENTIFIED BY 'SecurePassword123!';
-- Crear usuario sin contraseña (no recomendado)
CREATE USER 'test_user'@'localhost';
Paso 4: Otorgar Privilegios Básicos
Otorgue privilegios a usuarios para bases de datos específicas:
-- Otorgar todos los privilegios en una base de datos específica
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'localhost';
-- Otorgar privilegios específicos en una base de datos
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_user'@'localhost';
-- Otorgar solo SELECT en una base de datos
GRANT SELECT ON myapp_db.* TO 'readonly_user'@'localhost';
-- Otorgar privilegios en tabla específica
GRANT SELECT, INSERT ON myapp_db.users TO 'limited_user'@'localhost';
-- Otorgar privilegios específicos de columna
GRANT SELECT (id, username, email) ON myapp_db.users TO 'limited_user'@'localhost';
-- Aplicar cambios de privilegios
FLUSH PRIVILEGES;
Paso 5: Otorgar Privilegios Administrativos
Cree usuarios administrativos con diferentes niveles de acceso:
-- Crear administrador de base de datos (DBA)
CREATE USER 'dba_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON *.* TO 'dba_user'@'localhost' WITH GRANT OPTION;
-- Crear usuario de respaldo
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
GRANT RELOAD, PROCESS ON *.* TO 'backup_user'@'localhost';
-- Crear usuario de replicación
CREATE USER 'replication_user'@'%' IDENTIFIED BY 'SecurePassword123!';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replication_user'@'%';
-- Crear usuario de monitoreo
CREATE USER 'monitor_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor_user'@'localhost';
GRANT SELECT ON performance_schema.* TO 'monitor_user'@'localhost';
-- Aplicar cambios
FLUSH PRIVILEGES;
Paso 6: Ver Privilegios de Usuario
Verifique qué privilegios tiene un usuario:
-- Mostrar privilegios para el usuario actual
SHOW GRANTS;
-- Mostrar privilegios para usuario específico
SHOW GRANTS FOR 'app_user'@'localhost';
-- Mostrar información detallada de privilegios
SELECT * FROM mysql.user WHERE User = 'app_user'\G
-- Mostrar privilegios a nivel de base de datos
SELECT * FROM mysql.db WHERE User = 'app_user'\G
-- Mostrar privilegios a nivel de tabla
SELECT * FROM mysql.tables_priv WHERE User = 'app_user'\G
Paso 7: Modificar Privilegios de Usuario
Actualice privilegios de usuarios existentes:
-- Agregar privilegios adicionales
GRANT DELETE ON myapp_db.* TO 'app_user'@'localhost';
-- Eliminar privilegios específicos
REVOKE DELETE ON myapp_db.* FROM 'app_user'@'localhost';
-- Eliminar todos los privilegios para una base de datos
REVOKE ALL PRIVILEGES ON myapp_db.* FROM 'app_user'@'localhost';
-- Eliminar todos los privilegios globalmente
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'app_user'@'localhost';
-- Aplicar cambios
FLUSH PRIVILEGES;
Paso 8: Modificar Propiedades de Usuario
Cambie contraseñas y propiedades de cuenta de usuarios:
-- Cambiar contraseña de usuario
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'NewSecurePassword456!';
-- Cambiar método de autenticación
ALTER USER 'app_user'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'SecurePassword123!';
-- Expirar contraseña (forzar cambio en próximo inicio de sesión)
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE;
-- Establecer política de expiración de contraseña
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
-- Nunca expirar contraseña
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE NEVER;
-- Bloquear cuenta de usuario
ALTER USER 'app_user'@'localhost' ACCOUNT LOCK;
-- Desbloquear cuenta de usuario
ALTER USER 'app_user'@'localhost' ACCOUNT UNLOCK;
-- Establecer límite de conexión
ALTER USER 'app_user'@'localhost' WITH MAX_USER_CONNECTIONS 10;
Paso 9: Renombrar y Eliminar Usuarios
Gestione cuentas de usuario:
-- Renombrar usuario
RENAME USER 'old_username'@'localhost' TO 'new_username'@'localhost';
-- Eliminar usuario (elimina todos los privilegios)
DROP USER 'app_user'@'localhost';
-- Eliminar múltiples usuarios
DROP USER 'user1'@'localhost', 'user2'@'localhost';
-- Eliminar usuario si existe (sin error si no existe)
DROP USER IF EXISTS 'app_user'@'localhost';
Paso 10: Implementar Control de Acceso Basado en Roles (MySQL 8.0+)
Cree y use roles para una gestión de permisos más fácil:
-- Crear roles
CREATE ROLE 'app_developer', 'app_reader', 'app_admin';
-- Otorgar privilegios a roles
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_developer';
GRANT SELECT ON myapp_db.* TO 'app_reader';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_admin';
-- Asignar roles a usuarios
CREATE USER 'john'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT 'app_developer' TO 'john'@'localhost';
-- Establecer rol predeterminado
SET DEFAULT ROLE 'app_developer' TO 'john'@'localhost';
-- Ver otorgamientos de roles
SHOW GRANTS FOR 'john'@'localhost' USING 'app_developer';
-- Revocar rol de usuario
REVOKE 'app_developer' FROM 'john'@'localhost';
-- Eliminar rol
DROP ROLE 'app_developer';
Escenarios Avanzados de Permisos
Creación de Usuarios Específicos de Aplicación
Cree usuarios para diferentes componentes de la aplicación:
-- Usuario de aplicación web
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'webapp'@'localhost';
GRANT EXECUTE ON myapp_db.* TO 'webapp'@'localhost';
-- Usuario API con acceso limitado
CREATE USER 'api_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.users TO 'api_user'@'localhost';
GRANT SELECT ON myapp_db.products TO 'api_user'@'localhost';
GRANT INSERT ON myapp_db.orders TO 'api_user'@'localhost';
-- Usuario de reportes (solo lectura)
CREATE USER 'reports'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.* TO 'reports'@'localhost';
-- Usuario de procesamiento por lotes
CREATE USER 'batch_processor'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.transactions TO 'batch_processor'@'localhost';
GRANT SELECT ON myapp_db.users TO 'batch_processor'@'localhost';
FLUSH PRIVILEGES;
Implementación de Seguridad a Nivel de Fila
Use vistas para implementar seguridad a nivel de fila:
-- Crear tabla base
CREATE TABLE myapp_db.employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
department VARCHAR(50),
salary DECIMAL(10,2),
email VARCHAR(100)
);
-- Crear vista para departamento de RRHH
CREATE VIEW myapp_db.hr_employees AS
SELECT id, name, department, salary, email
FROM myapp_db.employees
WHERE department = 'HR';
-- Crear vista para otros departamentos (sin salario)
CREATE VIEW myapp_db.department_employees AS
SELECT id, name, department, email
FROM myapp_db.employees;
-- Otorgar acceso solo a vistas
CREATE USER 'hr_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE ON myapp_db.hr_employees TO 'hr_user'@'localhost';
CREATE USER 'dept_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.department_employees TO 'dept_user'@'localhost';
FLUSH PRIVILEGES;
Asegurar Procedimientos Almacenados
Controle el acceso a procedimientos almacenados:
-- Crear procedimiento almacenado
DELIMITER //
CREATE PROCEDURE myapp_db.update_user_email(
IN user_id INT,
IN new_email VARCHAR(100)
)
SQL SECURITY DEFINER
BEGIN
UPDATE myapp_db.users
SET email = new_email
WHERE id = user_id;
END //
DELIMITER ;
-- Otorgar privilegio de ejecución
CREATE USER 'proc_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT EXECUTE ON PROCEDURE myapp_db.update_user_email TO 'proc_user'@'localhost';
-- El usuario puede ejecutar el procedimiento sin acceso directo a tabla
FLUSH PRIVILEGES;
Gestión de Privilegios Temporales
Otorgue privilegios elevados temporales:
-- Otorgar acceso de administrador temporal
GRANT ALL PRIVILEGES ON myapp_db.* TO 'temp_admin'@'localhost';
FLUSH PRIVILEGES;
-- Después del mantenimiento, revocar
REVOKE ALL PRIVILEGES ON myapp_db.* FROM 'temp_admin'@'localhost';
GRANT SELECT ON myapp_db.* TO 'temp_admin'@'localhost';
FLUSH PRIVILEGES;
Implementación de Mejores Prácticas de Seguridad
Implementar Políticas de Contraseñas
Configure validación de contraseñas (MySQL 8.0+):
-- Instalar componente de validación de contraseñas
INSTALL COMPONENT 'file://component_validate_password';
-- Verificar configuraciones de validación de contraseñas
SHOW VARIABLES LIKE 'validate_password%';
-- Configurar política de contraseñas
SET GLOBAL validate_password.length = 12;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.number_count = 1;
SET GLOBAL validate_password.special_char_count = 1;
SET GLOBAL validate_password.policy = 'STRONG';
En my.cnf:
[mysqld]
validate_password.length = 12
validate_password.mixed_case_count = 1
validate_password.number_count = 1
validate_password.special_char_count = 1
validate_password.policy = STRONG
Habilitar Registro de Auditoría
Rastree actividades de usuarios:
-- Instalar plugin de auditoría (MariaDB)
INSTALL PLUGIN server_audit SONAME 'server_audit.so';
-- Configurar ajustes de auditoría
SET GLOBAL server_audit_logging = ON;
SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';
SET GLOBAL server_audit_file_path = '/var/log/mysql/audit.log';
Para MySQL Enterprise:
-- Instalar plugin de registro de auditoría
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
-- Configurar ajustes de auditoría
SET GLOBAL audit_log_policy = 'ALL';
SET GLOBAL audit_log_format = 'JSON';
Implementar Seguridad de Conexión
Requerir SSL/TLS para conexiones:
-- Requerir SSL para usuario
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'SecurePassword123!' REQUIRE SSL;
-- Requerir certificado SSL específico
CREATE USER 'cert_user'@'%' IDENTIFIED BY 'SecurePassword123!'
REQUIRE X509;
-- Requerir emisor específico
CREATE USER 'issuer_user'@'%' IDENTIFIED BY 'SecurePassword123!'
REQUIRE ISSUER '/C=US/ST=CA/L=City/O=Company/CN=CA';
-- Modificar usuario existente para requerir SSL
ALTER USER 'app_user'@'localhost' REQUIRE SSL;
Implementar Límites de Recursos de Cuenta
Controle el uso de recursos:
-- Crear usuario con límites de recursos
CREATE USER 'limited_user'@'localhost' IDENTIFIED BY 'SecurePassword123!'
WITH MAX_QUERIES_PER_HOUR 1000
MAX_UPDATES_PER_HOUR 500
MAX_CONNECTIONS_PER_HOUR 100
MAX_USER_CONNECTIONS 5;
-- Modificar límites de usuario existente
ALTER USER 'app_user'@'localhost'
WITH MAX_QUERIES_PER_HOUR 5000
MAX_USER_CONNECTIONS 10;
Monitoreo y Auditoría
Monitorear Conexiones Activas
Ver conexiones de usuario actuales:
-- Mostrar todas las conexiones
SELECT * FROM information_schema.PROCESSLIST;
-- Mostrar conexiones por usuario
SELECT User, Host, DB, Command, Time, State
FROM information_schema.PROCESSLIST
WHERE User = 'app_user';
-- Contar conexiones por usuario
SELECT User, COUNT(*) as connection_count
FROM information_schema.PROCESSLIST
GROUP BY User;
-- Mostrar consultas de larga duración
SELECT User, Host, DB, Time, State, Info
FROM information_schema.PROCESSLIST
WHERE Command != 'Sleep'
AND Time > 60
ORDER BY Time DESC;
Auditar Actividades de Usuario
Crear consultas de auditoría:
-- Verificar últimos cambios de contraseña
SELECT User, Host, password_last_changed
FROM mysql.user
WHERE password_last_changed IS NOT NULL
ORDER BY password_last_changed DESC;
-- Verificar cuentas bloqueadas
SELECT User, Host, account_locked
FROM mysql.user
WHERE account_locked = 'Y';
-- Verificar estado de expiración de contraseña
SELECT User, Host, password_expired, password_lifetime
FROM mysql.user;
-- Verificar usuarios con privilegio SUPER
SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y';
-- Verificar usuarios con privilegio GRANT
SELECT User, Host FROM mysql.user WHERE Grant_priv = 'Y';
Crear Script de Auditoría de Usuario
#!/bin/bash
# Script de Auditoría de Usuario de MySQL
sudo mysql -e "
SELECT 'Total Users' as Metric, COUNT(*) as Count FROM mysql.user
UNION ALL
SELECT 'Users with Global Privileges', COUNT(*) FROM mysql.user WHERE Select_priv = 'Y' OR Insert_priv = 'Y'
UNION ALL
SELECT 'Locked Accounts', COUNT(*) FROM mysql.user WHERE account_locked = 'Y'
UNION ALL
SELECT 'Expired Passwords', COUNT(*) FROM mysql.user WHERE password_expired = 'Y'
UNION ALL
SELECT 'Wildcard Host Users', COUNT(*) FROM mysql.user WHERE Host = '%';
"
Verificación y Pruebas
Probar Permisos de Usuario
# Probar conexión como usuario específico
mysql -u app_user -p -h localhost -e "SELECT DATABASE(), USER();"
# Probar permiso SELECT
mysql -u app_user -p myapp_db -e "SELECT * FROM users LIMIT 1;"
# Probar permiso INSERT
mysql -u app_user -p myapp_db -e "INSERT INTO test_table (data) VALUES ('test');"
# Probar permiso UPDATE
mysql -u app_user -p myapp_db -e "UPDATE test_table SET data='updated' WHERE id=1;"
# Probar permiso DELETE
mysql -u app_user -p myapp_db -e "DELETE FROM test_table WHERE id=1;"
# Probar permiso denegado (debería fallar)
mysql -u readonly_user -p myapp_db -e "DROP TABLE test_table;"
Verificar Configuración de Privilegios
-- Verificar que existe el usuario
SELECT COUNT(*) as user_exists
FROM mysql.user
WHERE User = 'app_user' AND Host = 'localhost';
-- Verificar privilegio específico
SELECT User, Host, Select_priv, Insert_priv, Update_priv, Delete_priv
FROM mysql.user
WHERE User = 'app_user';
-- Verificar acceso a base de datos
SELECT User, Host, Db, Select_priv, Insert_priv, Update_priv, Delete_priv
FROM mysql.db
WHERE User = 'app_user' AND Db = 'myapp_db';
-- Verificar escalación de privilegios
SELECT User, Host FROM mysql.user WHERE Grant_priv = 'Y';
Solución de Problemas
Errores de Acceso Denegado
Problema: ERROR 1045 (28000): Access denied for user
Solución: Verifique credenciales de usuario y host:
-- Verificar si existe el usuario
SELECT User, Host FROM mysql.user WHERE User = 'app_user';
-- Verificar plugin de autenticación
SELECT User, Host, plugin FROM mysql.user WHERE User = 'app_user';
-- Restablecer contraseña
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'NewPassword123!';
FLUSH PRIVILEGES;
-- Verificar conexión desde el host correcto
-- El usuario debe conectarse desde el host coincidente en la definición user@host
Desde línea de comandos:
# Verificar registro de errores de MySQL
sudo tail -f /var/log/mysql/error.log
# Probar conexión con error detallado
mysql -u app_user -p -h localhost -v -e "SELECT 1;"
Permiso Denegado en Operaciones
Problema: ERROR 1142 (42000): command denied to user
Solución: Otorgue los privilegios necesarios:
-- Verificar privilegios actuales
SHOW GRANTS FOR 'app_user'@'localhost';
-- Otorgar privilegio faltante
GRANT CREATE ON myapp_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
-- Verificar que se otorgó el privilegio
SHOW GRANTS FOR 'app_user'@'localhost';
Errores de Host No Permitido
Problema: ERROR 1130 (HY000): Host '192.168.1.100' is not allowed to connect
Solución: Cree usuario para host específico:
-- Crear usuario para IP específica
CREATE USER 'app_user'@'192.168.1.100' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'192.168.1.100';
-- O permitir desde cualquier host (menos seguro)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;
Verificar bind-address en my.cnf:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
bind-address = 0.0.0.0 # Permitir conexiones externas
Reiniciar MySQL:
sudo systemctl restart mysql
Demasiadas Conexiones
Problema: ERROR 1040 (HY000): Too many connections
Solución: Ajuste los límites de conexión:
-- Verificar conexiones actuales
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
-- Aumentar conexiones máximas
SET GLOBAL max_connections = 200;
-- Verificar límites por usuario
SELECT User, Host, max_user_connections FROM mysql.user;
-- Aumentar límite de conexión de usuario
ALTER USER 'app_user'@'localhost' WITH MAX_USER_CONNECTIONS 20;
En my.cnf:
[mysqld]
max_connections = 200
Privilegio No Toma Efecto
Problema: Privilegio otorgado no funciona inmediatamente
Solución: Limpie privilegios:
-- Limpiar tablas de privilegios
FLUSH PRIVILEGES;
-- O reiniciar MySQL
-- sudo systemctl restart mysql
-- Forzar reconexión de usuario
SELECT * FROM information_schema.PROCESSLIST WHERE User = 'app_user';
-- Anotar IDs de proceso y matarlos
KILL <process_id>;
Resumen de Mejores Prácticas
1. Principio de Menor Privilegio
Otorgue solo los privilegios mínimos necesarios para que cada usuario realice sus tareas. Revise y audite regularmente los permisos de usuario.
2. Use Contraseñas Fuertes
Implemente políticas de contraseñas que requieran:
- Longitud mínima de 12 caracteres
- Mezcla de mayúsculas, minúsculas, números y caracteres especiales
- Rotación regular de contraseñas (90 días)
- Sin reutilización de contraseñas
3. Evite Usar Root para Aplicaciones
Nunca use la cuenta root para conexiones de aplicación. Cree usuarios dedicados con privilegios apropiados.
4. Restrinja el Acceso de Host
Use direcciones IP específicas o nombres de host en lugar del comodín '%' cuando sea posible:
-- Bueno
CREATE USER 'app_user'@'192.168.1.100' IDENTIFIED BY 'password';
-- Menos seguro
CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';
5. Use Roles para Entornos Complejos
Implemente control de acceso basado en roles (RBAC) para facilitar la gestión de permisos entre múltiples usuarios.
6. Habilite SSL/TLS
Requiera conexiones cifradas para todos los usuarios remotos:
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
7. Auditorías de Seguridad Regulares
Programe auditorías de seguridad mensuales:
- Revisar todas las cuentas de usuario
- Verificar cuentas no utilizadas
- Verificar asignaciones de privilegios
- Revisar registros de auditoría
- Verificar permisos de host comodín
8. Documente los Propósitos de Usuario
Mantenga documentación para cada usuario de base de datos:
- Propósito y propietario
- Fecha de creación
- Privilegios otorgados
- Calendario de revisión
- Información de contacto
9. Implemente Expiración de Cuenta
Establezca fechas de expiración para cuentas temporales:
ALTER USER 'temp_user'@'localhost' PASSWORD EXPIRE INTERVAL 30 DAY;
10. Monitoree y Alerte
Configure monitoreo para:
- Intentos fallidos de inicio de sesión
- Intentos de escalación de privilegios
- Patrones de consulta inusuales
- Picos de conexión
- Cuentas bloqueadas
Conclusión
La gestión efectiva de usuarios y permisos en MySQL y MariaDB es fundamental para la seguridad de bases de datos y la eficiencia operativa. Siguiendo esta guía completa, ha aprendido cómo crear usuarios con privilegios apropiados, implementar control de acceso basado en roles, asegurar conexiones con SSL/TLS, auditar actividades de usuarios y solucionar problemas comunes de permisos.
La clave para mantener un entorno MySQL/MariaDB seguro es la vigilancia continua a través de auditorías regulares, adhesión al principio de menor privilegio, implementación de mecanismos de autenticación fuertes, monitoreo de actividades de usuario y mantenerse actualizado con las mejores prácticas de seguridad. Recuerde que la seguridad no es una configuración única sino un proceso continuo que requiere atención y actualizaciones regulares.
A medida que su entorno de base de datos crece, revise su estructura de permisos regularmente para asegurarse de que todavía cumple con sus requisitos de seguridad mientras apoya las necesidades operativas. Implemente sistemas de monitoreo y alerta automatizados para detectar actividades anómalas, realice capacitación de seguridad regular para los miembros del equipo con acceso a la base de datos, mantenga documentación completa de todas las cuentas de usuario y sus propósitos, y establezca procedimientos claros para otorgar, modificar y revocar privilegios.
La base que ha construido con esta guía le servirá bien a medida que escale su infraestructura de base de datos y se adapte a las amenazas de seguridad en evolución. Continúe manteniéndose informado sobre nuevas características de seguridad en las versiones de MySQL y MariaDB, participe en la comunidad de seguridad de bases de datos y pruebe regularmente sus configuraciones de seguridad para asegurar que proporcionen la protección que sus datos merecen.


