Saltar al contenido
usuarios-y-permisos.sql · devschool

Usuarios y permisos en SQL

Lección 22 de 22 · 10 min de lectura · Actualizado el

En esta lección
  1. DCL: el lenguaje de los permisos
  2. Crear un usuario: CREATE USER
  3. Dar permisos: GRANT
  4. Ver los permisos: SHOW GRANTS
  5. Quitar permisos: REVOKE
  6. Roles: grupos de permisos
  7. Cambiar la contraseña y borrar usuarios
  8. El principio de mínimo privilegio
  9. Otras bases de datos
  10. Errores frecuentes
  11. Resumen

Una base de datos real no la usa una sola persona. La usan la aplicación web, el equipo de desarrollo, alguien de administración que saca informes… y no todos deberían poder hacer lo mismo. En esta lección aprenderás a crear usuarios, a darles solo los permisos que necesitan y a quitárselos cuando ya no los necesiten. Todos los ejemplos usan la sintaxis de MySQL 8.

DCL: el lenguaje de los permisos

Las instrucciones de SQL se suelen agrupar en familias según para qué sirven:

FamiliaSignificadoInstrucciones
DDLDefinición de datosCREATE, ALTER, DROP
DMLManipulación de datosSELECT, INSERT, UPDATE, DELETE
DCLControl de datosGRANT, REVOKE
TCLControl de transaccionesCOMMIT, ROLLBACK, SAVEPOINT

El DCL (Data Control Language) decide quién puede hacer qué. Para usarlo necesitas conectarte con un usuario que tenga permiso para crear usuarios y repartir permisos, normalmente root o un administrador.

Crear un usuario: CREATE USER

CREATE USER 'ana'@'localhost' IDENTIFIED BY 'Cl4ve_Segura_2026';

Un usuario de MySQL tiene dos partes: el nombre ('ana') y el host desde el que se conecta ('localhost'), separados por @. La contraseña va después de IDENTIFIED BY.

El host

El host indica desde qué máquina se permite la conexión:

HostSignificado
'localhost'Solo desde el mismo ordenador donde está MySQL
'192.168.1.20'Solo desde esa IP
'192.168.1.%'Desde cualquier IP que empiece así (% es un comodín)
'%'Desde cualquier sitio

Esto es una capa de seguridad más: aunque alguien robe la contraseña de 'ana'@'localhost', no podrá usarla desde fuera del servidor.

Cuidado: para MySQL, 'ana'@'localhost' y 'ana'@'%' son dos usuarios distintos, con su propia contraseña y sus propios permisos. Si no indicas el host (CREATE USER 'ana'), se entiende 'ana'@'%'.

Para ver los usuarios que existen, consulta la tabla interna mysql.user:

SELECT user, host FROM mysql.user;

Un usuario recién creado puede conectarse, pero no puede hacer nada: no ve ninguna base de datos. Hay que darle permisos.

Dar permisos: GRANT

La forma general es GRANT permisos ON dónde TO usuario:

GRANT SELECT, INSERT ON tienda.* TO 'ana'@'localhost';

Ahora Ana puede leer y añadir filas en todas las tablas de la base de datos tienda, pero no modificarlas ni borrarlas.

Los permisos más habituales

PermisoPermite
SELECTLeer datos
INSERTAñadir filas
UPDATEModificar filas
DELETEBorrar filas
CREATE, ALTER, DROPCrear, cambiar y borrar tablas
INDEXCrear y borrar índices
CREATE VIEWCrear vistas
ALL PRIVILEGESTodos los anteriores y más

Niveles: dónde se aplica el permiso

Lo que va después de ON indica el alcance:

-- Toda la base de datos tienda
GRANT SELECT ON tienda.* TO 'ana'@'localhost';

-- Solo la tabla pedidos
GRANT SELECT, UPDATE ON tienda.pedidos TO 'luis'@'localhost';

-- Solo algunas columnas de clientes
GRANT SELECT (id, nombre, ciudad) ON tienda.clientes TO 'marketing'@'%';

-- Todo en todas las bases de datos (¡solo para administradores!)
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost';

El nivel de columna es poco habitual. Para ocultar columnas o filas suele ser más cómodo crear una vista y dar permiso solo sobre ella:

GRANT SELECT ON tienda.clientes_publicos TO 'marketing'@'%';

Por defecto, un usuario no puede pasar sus permisos a otros. Si quieres que pueda, añade WITH GRANT OPTION al final del GRANT. Úsalo con mucha prudencia.

Nota: en MySQL 8, GRANT ya no crea usuarios. En versiones antiguas se podía escribir GRANT ... IDENTIFIED BY ... para crear el usuario y darle permisos a la vez; ahora da error. Primero CREATE USER, después GRANT. Tampoco hace falta FLUSH PRIVILEGES después de un GRANT: los cambios se aplican al momento.

Ver los permisos: SHOW GRANTS

SHOW GRANTS FOR 'ana'@'localhost';
GRANT USAGE ON *.* TO `ana`@`localhost`
GRANT SELECT, INSERT ON `tienda`.* TO `ana`@`localhost`

USAGE significa “ningún permiso”: es la línea que tiene cualquier usuario, solo indica que existe y puede conectarse. La segunda línea son sus permisos reales. Para ver los tuyos, escribe solo SHOW GRANTS;.

Quitar permisos: REVOKE

REVOKE es el contrario de GRANT, con FROM en lugar de TO:

REVOKE INSERT ON tienda.* FROM 'ana'@'localhost';

Ahora Ana solo conserva SELECT. Un detalle importante: tienes que quitar el permiso al mismo nivel al que lo diste. Si diste SELECT en tienda.*, un REVOKE SELECT ON tienda.clientes no funciona, porque ese permiso no existe a nivel de tabla.

Roles: grupos de permisos

Si tienes diez personas que necesitan los mismos permisos, darlos uno a uno es pesado y fácil de equivocar. MySQL 8 tiene roles: un conjunto de permisos con nombre que luego asignas a los usuarios.

-- 1. Crear el rol y darle permisos
CREATE ROLE 'lectura_tienda';
GRANT SELECT ON tienda.* TO 'lectura_tienda';

-- 2. Asignar el rol a los usuarios
GRANT 'lectura_tienda' TO 'ana'@'localhost', 'luis'@'localhost';

-- 3. Activarlo por defecto al conectarse
SET DEFAULT ROLE 'lectura_tienda' TO 'ana'@'localhost', 'luis'@'localhost';

Si mañana el rol necesita un permiso más, se lo das al rol y todos sus usuarios lo tienen al momento.

Cuidado: en MySQL, un rol asignado no está activo hasta que se activa. Si te saltas el paso 3, el usuario tendrá que escribir SET ROLE 'lectura_tienda'; en cada conexión, o le parecerá que no tiene permisos. Con SELECT CURRENT_ROLE(); ves los roles activos.

Cambiar la contraseña y borrar usuarios

Para cambiar la contraseña de un usuario se usa ALTER USER:

ALTER USER 'ana'@'localhost' IDENTIFIED BY 'Nueva_Cl4ve_2026';

Con ALTER USER también puedes obligar a cambiarla en la próxima conexión (PASSWORD EXPIRE) o bloquear temporalmente una cuenta (ACCOUNT LOCK, y ACCOUNT UNLOCK para desbloquearla).

Para eliminar un usuario y todos sus permisos:

DROP USER 'ana'@'localhost';

Nota: MySQL 8 puede tener activada la validación de contraseñas, que rechaza las débiles con un error. Usa contraseñas largas, con mayúsculas, números y símbolos.

El principio de mínimo privilegio

La regla de oro de la seguridad es dar a cada usuario solo los permisos que necesita para su trabajo, y ninguno más. Si un usuario solo consulta, no necesita DELETE. Si solo trabaja con la tienda, no necesita acceso a la base de datos de nóminas.

¿Por qué tanta precaución? Porque los errores y los ataques ocurren. Si alguien consigue entrar con un usuario que solo tiene SELECT sobre una tabla, el daño es limitado. Si entra con root, puede borrarlo todo.

El usuario de la aplicación frente a root

El error más común en proyectos de clase (y en demasiados proyectos reales) es que la aplicación web se conecte a la base de datos como root. Lo correcto es crear un usuario específico para ella:

CREATE USER 'app_tienda'@'localhost' IDENTIFIED BY 'Cl4ve_Larga_Y_Aleatoria_91';
GRANT SELECT, INSERT, UPDATE, DELETE ON tienda.* TO 'app_tienda'@'localhost';

Este usuario puede leer y modificar datos de la tienda, que es lo que hace la aplicación en su día a día. No puede crear ni borrar tablas, ni ver otras bases de datos, ni crear usuarios. Si un atacante encuentra un fallo de inyección SQL en tu web, al menos no podrá hacer DROP DATABASE.

Un reparto típico en una empresa:

UsuarioPermisosPara qué
rootTodosSolo administración, nunca en aplicaciones
app_tiendaSELECT, INSERT, UPDATE, DELETE en tienda.*La aplicación web
migracionesAdemás CREATE, ALTER, DROP, INDEX en tienda.*Cambios de estructura al desplegar
informesSELECT sobre algunas vistasPaneles y análisis

Otras bases de datos

Nota sobre PostgreSQL: todo son roles. Un usuario es simplemente un rol que puede iniciar sesión: CREATE ROLE ana LOGIN PASSWORD 'Cl4ve_Segura'; (o CREATE USER ana PASSWORD '...', que es lo mismo). El nombre no lleva @host: desde dónde se puede conectar se configura aparte, en el archivo pg_hba.conf. Los permisos son parecidos, aunque se organizan por esquemas: GRANT SELECT ON ALL TABLES IN SCHEMA public TO ana;. Y los roles asignados se heredan sin necesidad de activarlos.

SQLite no tiene usuarios ni permisos. Una base de datos SQLite es un archivo: quien puede leer ese archivo puede leer todos los datos. La seguridad depende de los permisos del sistema operativo sobre el archivo. Por eso no tiene GRANT ni REVOKE.

Errores frecuentes

  • Conectar la aplicación como root. Crea siempre un usuario con los permisos justos.
  • Usar '%' sin necesidad. Si la aplicación y la base de datos están en el mismo servidor, 'localhost' es más seguro.
  • Confundir usuarios con distinto host. Das permisos a 'ana'@'%' y te conectas como 'ana'@'localhost': son usuarios distintos y el segundo no tiene esos permisos.
  • GRANT ALL PRIVILEGES ON *.* “para que funcione”. Funciona, pero has creado otro root.
  • Olvidar activar los roles con SET DEFAULT ROLE.
  • Escribir contraseñas en el código fuente que subes a GitHub. Guárdalas en variables de entorno o en un archivo de configuración fuera del repositorio.

Resumen

InstrucciónQué hace
CREATE USER 'u'@'host' IDENTIFIED BY 'clave'Crea un usuario
GRANT permisos ON bd.tabla TO 'u'@'host'Da permisos
REVOKE permisos ON bd.tabla FROM 'u'@'host'Quita permisos
SHOW GRANTS FOR 'u'@'host'Muestra los permisos de un usuario
CREATE ROLE 'r' y GRANT 'r' TO 'u'@'host'Agrupa permisos en un rol y lo asigna
SET DEFAULT ROLE 'r' TO 'u'@'host'Activa el rol al conectarse
ALTER USER 'u'@'host' IDENTIFIED BY 'nueva'Cambia la contraseña
DROP USER 'u'@'host'Borra el usuario
  • En MySQL, un usuario es nombre + host.
  • Los permisos se dan a nivel global (*.*), de base de datos (tienda.*), de tabla o de columna.
  • Aplica siempre el mínimo privilegio: cada usuario, solo lo que necesita.
  • Con esta lección terminas el curso de SQL. Si quieres usar todo esto desde un programa, sigue con JDBC en Java.

Pon a prueba lo que has aprendido

[SQL] ¿Qué puede hacer Ana después de estas instrucciones?
CREATE USER 'ana'@'localhost' IDENTIFIED BY 'Cl4ve_Segura_2026';
GRANT SELECT, INSERT, UPDATE ON tienda.* TO 'ana'@'localhost';
REVOKE UPDATE ON tienda.* FROM 'ana'@'localhost';

[SQL] En MySQL, ¿qué relación hay entre 'ana'@'localhost' y 'ana'@'%'?

[SQL] ¿Qué permisos debería tener el usuario con el que se conecta una aplicación web de tienda?

[SQL] Asignas un rol a un usuario en MySQL 8 con GRANT 'lectura_tienda' TO 'luis'@'localhost', pero Luis dice que no puede consultar nada. ¿Qué falta lo más probable?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.