GRANT

Una vez que has creado un usuario con CREATE USER, ese usuario puede conectarse al servidor pero no tiene permisos para hacer nada útil. La sentencia GRANT es el mecanismo que MySQL proporciona para asignar privilegios específicos a cada cuenta de usuario. Con ella puedes controlar exactamente qué operaciones puede realizar cada usuario, sobre qué bases de datos, tablas o incluso columnas específicas.

Un sistema de privilegios bien configurado es la base de la seguridad en MySQL. Seguir el principio de mínimo privilegio, es decir, otorgar solo los permisos estrictamente necesarios, reduce significativamente el riesgo de modificaciones accidentales o accesos no autorizados a información sensible.

Sintaxis

La sintaxis general de GRANT es:

GRANT privilegio1, privilegio2, ...
    ON nivel_de_privilegio
    TO 'usuario'@'host';

Donde nivel_de_privilegio define el alcance de los permisos y puede tomar varias formas según el nivel deseado:

*.*                     -- Nivel global (todas las bases de datos)
nombre_base.*           -- Nivel de base de datos
nombre_base.nombre_tabla -- Nivel de tabla

Comportamiento básico

Cuando ejecutas un GRANT, MySQL registra el privilegio en las tablas del sistema (mysql.user, mysql.db, mysql.tables_priv o mysql.columns_priv, según el nivel). Los privilegios se aplican de forma acumulativa: si otorgas SELECT y después otorgas INSERT al mismo usuario sobre el mismo objeto, el usuario tendrá ambos privilegios.

GRANT SELECT ON tienda.productos TO 'analista'@'localhost';

Este comando otorga al usuario analista el privilegio de ejecutar consultas SELECT únicamente sobre la tabla productos de la base de datos tienda. No podrá modificar datos, ni acceder a otras tablas.

Para que los cambios surtan efecto de forma inmediata en conexiones ya establecidas, puedes ejecutar:

FLUSH PRIVILEGES;

Sin embargo, en la mayoría de los casos, MySQL aplica automáticamente los privilegios otorgados con GRANT sin necesidad de ejecutar FLUSH PRIVILEGES.

Niveles de privilegio

MySQL organiza los privilegios en cuatro niveles jerárquicos. Cada nivel tiene un alcance distinto y se almacena en una tabla diferente del esquema mysql.

Nivel global afecta a todas las bases de datos del servidor. Los privilegios globales se almacenan en mysql.user:

GRANT ALL PRIVILEGES ON *.* TO 'admin_total'@'localhost';

Nivel de base de datos afecta a todas las tablas dentro de una base de datos específica. Se almacenan en mysql.db:

GRANT SELECT, INSERT, UPDATE, DELETE ON tienda.* TO 'app_tienda'@'10.0.1.%';

Nivel de tabla afecta únicamente a una tabla concreta. Se almacenan en mysql.tables_priv:

GRANT SELECT, UPDATE ON tienda.inventario TO 'almacenero'@'localhost';

Nivel de columna permite restringir el acceso a columnas específicas de una tabla. Se almacenan en mysql.columns_priv:

GRANT SELECT (nombre, email) ON tienda.clientes TO 'marketing'@'192.168.1.%';

En este último ejemplo, el usuario marketing solo puede ver las columnas nombre y email de la tabla clientes, sin acceso a datos sensibles como dirección o teléfono.

Caso práctico: privilegios para una aplicación web

Supongamos que tienes una aplicación de comercio electrónico con una base de datos llamada ecommerce. Necesitas configurar distintos niveles de acceso para diferentes componentes de la aplicación.

La cuenta principal de la aplicación necesita realizar operaciones CRUD completas:

GRANT SELECT, INSERT, UPDATE, DELETE
    ON ecommerce.*
    TO 'webapp_prod'@'10.0.1.15';

El microservicio de reportes solo necesita leer datos:

GRANT SELECT ON ecommerce.* TO 'servicio_reportes'@'10.0.2.%';

El proceso de migración necesita además modificar la estructura de las tablas:

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX
    ON ecommerce.*
    TO 'migraciones'@'localhost';

Para verificar los privilegios asignados a cada usuario puedes usar SHOW GRANTS:

SHOW GRANTS FOR 'webapp_prod'@'10.0.1.15';
Grants for webapp_prod@10.0.1.15
GRANT USAGE ON . TO webapp_prod@10.0.1.15
GRANT SELECT, INSERT, UPDATE, DELETE ON ecommerce.* TO webapp_prod@10.0.1.15

El privilegio USAGE aparece siempre y significa que el usuario puede conectarse al servidor. No otorga ningún permiso adicional por sí mismo.

Caso práctico: WITH GRANT OPTION

En organizaciones grandes, a veces necesitas que ciertos administradores puedan delegar privilegios a otros usuarios sin intervención del DBA principal. Para esto existe la cláusula WITH GRANT OPTION.

GRANT SELECT, INSERT, UPDATE, DELETE
    ON rrhh.*
    TO 'jefe_rrhh'@'localhost'
    WITH GRANT OPTION;

Ahora el usuario jefe_rrhh puede, a su vez, otorgar a otros usuarios cualquiera de los privilegios que posee sobre la base de datos rrhh:

-- Ejecutado por jefe_rrhh después de conectarse
GRANT SELECT ON rrhh.empleados TO 'asistente_rrhh'@'localhost';

Esto es posible porque jefe_rrhh tiene GRANT OPTION. Sin embargo, no podría otorgar privilegios que él mismo no posee. Por ejemplo, no podría otorgar DROP porque él solo tiene SELECT, INSERT, UPDATE y DELETE.

Caso práctico: privilegios comunes y sus efectos

MySQL define más de treinta privilegios distintos. Los más utilizados en el día a día son los siguientes:

-- Lectura de datos
GRANT SELECT ON contabilidad.* TO 'contador'@'localhost';
 
-- Inserción de registros nuevos
GRANT INSERT ON contabilidad.facturas TO 'facturador'@'localhost';
 
-- Modificación de registros existentes
GRANT UPDATE ON contabilidad.facturas TO 'facturador'@'localhost';
 
-- Eliminación de registros
GRANT DELETE ON contabilidad.facturas_borrador TO 'facturador'@'localhost';
 
-- Ejecución de procedimientos almacenados
GRANT EXECUTE ON contabilidad.* TO 'app_contable'@'10.0.1.%';
 
-- Creación de tablas temporales
GRANT CREATE TEMPORARY TABLES ON contabilidad.* TO 'app_contable'@'10.0.1.%';

Para otorgar todos los privilegios sobre una base de datos específica se utiliza ALL PRIVILEGES:

GRANT ALL PRIVILEGES ON contabilidad.* TO 'dba_contabilidad'@'localhost';

Esto otorga todos los privilegios aplicables al nivel de base de datos, incluyendo CREATE, DROP, ALTER, INDEX, CREATE VIEW y muchos más. Sin embargo, no incluye GRANT OPTION a menos que lo especifiques explícitamente.

Advertencia: Evita otorgar ALL PRIVILEGES ON *.* a cuentas de aplicación. Este nivel de acceso es equivalente a una cuenta de superusuario y un error en la aplicación o una vulnerabilidad de seguridad podría comprometer todo el servidor. Reserva los privilegios globales totales exclusivamente para cuentas administrativas.

Consejo: Puedes usar SHOW GRANTS FOR CURRENT_USER() para inspeccionar los privilegios de tu propia sesión actual. Esto resulta útil cuando necesitas verificar si tienes los permisos necesarios para ejecutar una operación específica.

En el siguiente artículo aprenderás a revocar privilegios con la sentencia REVOKE.

Escrito por Eduardo Lázaro