O objetivo principal deste artigo é descrever os mecanismos de controles de acessos do MySQL, bem como apresentar as rotinas para criação de usuários e gerenciamento de seus privilégios.

O MySQL possui um mecanismo que permite limitar o acesso de um usuário a apenas um banco, tabela ou coluna, além de poder controlar o acesso de acordo com o host a partir de onde está sendo feita a conexão com o servidor. Pode-se ainda, conceder privilégios diferentes para cada host de onde o usuário possa estabelecer a conexão. Assim, é possível que determinados comandos possam ser executados somente quando o usuário estiver em um host específico, por exemplo o mesmo host do servidor MySQL (localhost).

O MySQL armazena as informações dos seus usuários em 4 tabelas que estão localizadas no banco de dados mysql. Estas tabelas são a user, db, tables_priv e columns_priv. A tabela user armazena as informações de todos os usuários do banco e os privilégios globais deste usuário. A tabela db armazena os privilégios dos usuários específicos de um banco de dados. Finalmente, as tabelas tables_priv e columns_priv armazenam os privilégios associados a tabelas e colunas, respectivamente. Como estas tabelas possuem as informações dos usuários, bem como os seus privilégios, recomenda-se que apenas o administrador do banco de dados tenha acesso ao banco mysql (usuário root).

Para criar usuários e conceder privilégios no MySQL, utiliza-se o comando GRANT. Ao executar um comando GRANT para um usuário que não existe, o mesmo será criado. Um GRANT para um usuário já existente adicionará os novos privilégios aos já concedidos anteriormente. A sintáxe resumida do comando GRANT é exibida a seguir:

GRANT priv [(colunas)] [, priv [(colunas)]] ...
ON {*.* | db.* | db.tabela}
TO usuario [IDENTIFIED BY 'senha']
[, usuario [IDENTIFIED BY 'senha']] ...
[WITH [GRANT OPTION |
MAX_QUERIES_PER_HOUR contador |
MAX_UPDATES_PER_HOUR contador |
MAX_CONNECTIONS_PER_HOUR contador]]

No comando acima os [ ] indicam que o comando é opcional. O primeiro item a ser informado é(são) o(s) privilégio(s) a ser(em) concedido(s) ao(s) usuário(s). A lista de privilégios existentes no MySQL é descrita abaixo:

Privilégio Descrição
ALL [PRIVILEGES] Todos os privilégios exceto GRANT OPTION
ALTER Permite executar ALTER TABLE
CREATE Permite executar CREATE TABLE
CREATE TEMPORARY TABLES Permite executar CREATE TEMPORARY TABLE
DELETE Permite executar DELETE
DROP Permite executar DROP TABLE
EXECUTE Permite executar stored procedures (MySQL 5.0)
FILE Permite executar SELECT ... INTO OUTFILE e LOAD DATA INFILE
INDEX Permite executar CREATE INDEX e DROP INDEX
INSERT Permite executar INSERT
LOCK TABLES Permite executar LOCK TABLES em tabelas que você tenha o privilégio SELECT
PROCESS Permite executar SHOW FULL PROCESSLIST
REFERENCES Ainda não está implementado
RELOAD Permite executar FLUSH
REPLICATION CLIENT Permite ao usuário obter a localização do Master ou Slave
REPLICATION SLAVE Necessário para a replicação Slave (leitura dos eventos do log binário do Master)
SELECT Permite executar SELECT
SHOW DATABASES exibe todos os bancos de dados
SHUTDOWN Permite executar mysqladmin shutdown
SUPER Permite executar CHANGE MASTER, KILL , PURGE MASTER LOGS e SET GLOBAL. Permite conectar-se ao servidor uma vez, mesmo que o max_connections tenha sido atingido
UPDATE Permite executar UPDATE
USAGE Sinônimo para "no privileges''
GRANT OPTION Permite ao usuário repassar os seus privilégios

Uma vez informados os privilégios do usuário, você deverá indicar o nível ao qual o privilégio se aplica, sendo possível especificar três níveis:

*.* Privilégio global
db.* Qualquer tabela do banco db
db.tb Apenas a tabela tb do banco de dados db. Para especificar apenas algumas colunas de uma determinada tabela, estas deverão ser listadas ao lado do privilégio (priv (colunas))

Depois do nível você deverá indicar o usuário, ou a lista de usuários, para os quais os privilégios se aplicam. No MySQL o usuário é constituído de um nome mais o host de onde ele poderá acessar o servidor (user@host). Caso você não informe o host para o usuário, o MySQL assumirá "%", isto é, todos os hosts. A senha do usuário é opcional, mas é recomendado sempre informá-la no momento de criação do usuário, por questões de segurança. Para adicionar privilégios a um usuário existente o IDENTIFIED BY poderá ser omitido. No exemplo a seguir é criado um usuário com o nome teste que pode se conectar somente do host onde o servidor está em execução (localhost), o usuário só poderá fazer SELECT nas colunas nome e idade da tabela pessoa, que se encontra no banco de dados rh. A senha do usuário é 12345.

GRANT SELECT (nome, idade) ON rh.pessoa TO teste@localhost
IDENTIFIED BY "12345";

Para listar os privilégios deste usuário utilize o comando:

SHOW GRANTS FOR teste@localhost;

Você pode especificar um conjunto de hosts utilizando o caracter "%", neste caso é possível dar acesso a um usuário dentro de uma faixa de IPs ou DNS. Usuários anônimos também podem ser criados informando um nome com o caracter espaço (" "). No exemplo a seguir, o usuário remoto poderá executar UPDATE e INSERT em qualquer tabela do banco de dados rh, sendo possível a conexão ao servidor a partir de qualquer máquina no domínio mysqlbrasil.com.br:

GRANT UPDATE, INSERT ON rh.* TO remoto@"%.mysqlbrasil.com.br"
IDENTIFIED BY "remoto";

Ou utilizando IP:

GRANT UPDATE, INSERT ON rh.* TO remoto@"200.236.13.%" IDENTIFIED BY "remoto";

Um usuário anônimo com os mesmos privilégios do usuário remoto seria criado da seguinte forma:

GRANT UPDATE, INSERT ON rh.* TO " "@"%mysqlbrasil.com.br"
IDENTIFIED BY "anonimo";

Finalmente, a opção GRANT OPTION é utilizada para que o usuário possa conceder os seus privilégios para outros usuários do banco. Além disto, você poderá limitar os recursos do usuário com as opções MAX_QUERIES_PER_HOUR, MAX_UPDATES_PER_HOUR ou MAX_CONNECTIONS_PER_HOUR.

Para remover um privilégio do usuário utilize o comando REVOKE mostrado abaixo:

REVOKE priv [(colunas)] [, priv [(colunas)]] ...
ON {*.* | db.* | db.tabela}
FROM usuario [, usuario] ...

Lembre-se de que a parte ON do REVOKE deverá coincidir com a parte ON do GRANT que você deseja remover, caso isto não se verifique o comando REVOKE não terá efeito algum. Além disto, o comando REVOKE remove apenas os privilégios do usuário, mas o usuário continuará existindo. A remoção do usuário deverá ser feita com um DELETE explícito na tabela de usuários do MySQL, após terem sido Removidos todos os seus privilégios com o comando REVOKE. Observe que para remover o usuário você deverá ter privilégio para executar DELETE na tabela user do mysql. Geralmente, esta tarefa é executada pelo administrador do banco (root).

DELETE FROM mysql.user WHERE user="teste" AND host="localhost";

Feito isto, você terá que executar um comando FLUSH PRIVILEGES para que o MySQL possa atualizar os privilégios que estão em memória.

FLUSH PRIVILEGES;

Aqui estamos descrevendo os comandos para a manipulação de usuários, sendo que esta é a maneira de entendermos como funciona a criação de usuários no MySQL. Uma forma mais intuitiva para executar esta tarefa pode ser encontrada no MySQL Administrator, que foi apresentado no último artigo.

Problemas para a conexão com o MySQL a partir do localhost

Ao instalar o MySQL são criados o usuário root com todos os privilégios (administrador), podendo se conectar somente do host local sem senha, e o usuário anônimo com privilégios apenas no banco de dados test, que pode se conectar apenas do host local sem senha. Para autentiticar um usuário durante a conexão com o servidor, o MySQL armazena em memória a listas de todos usuários, hosts e senhas cadastrados no banco e as ordena do host mais específico para o menos específico. Caso existam dois hosts iguais, os usuários mais específicos virão antes do usuário anônimo. Feito isto, a cada conexão será pesquisada nesta lista a primeira ocorrência que coincida o host, usuário e senha informados no momento da tentativa de conexão. Tomemos o caso em que após a instalação do MySQL, criamos um usuário que possa se conectar a partir de qualquer host dentro do domínio onde se encontra o servidor MySQL:

GRANT ALL ON rh.* TO user@"192.168.0.%" IDENTIFIED BY "12345";

Neste caso, o MySQL cria em memória a lista dos usuários da seguinte forma:

Usuário Senha
root@localhost
" "@localhost 
user@"192.168.0.%" 12345

Este usuário será capaz de se conectar ao servidor MySQL a partir de qualquer máquina no domínio, exceto o host local, pois neste caso, ao pesquisar na lista pelo user@localhost, a primeira ocorrência encontrada é a do usuário anônimo, já que qualquer usuário pode ser considerado anônimo pelo MySQL. O detalhe é que as senhas destes usuários não coincidem, o que gera um erro de "Acesso Negado". Para evitar a situação acima você deverá excluir o usuário anônimo ou adicionar o mesmo usuário para se conectar remoto e a partir do host local, da seguinte forma:

GRANT ALL ON rh.* TO user@"192.168.0.%" IDENTIFIED BY "12345",
user@localhost IDENTIFIED BY "12345";

Assim a ordenação ficaria:

Usuário Senha
root@localhost
user@localhost 12345
" "@localhost 
user@"192.168.0.%" 12345

Desta forma, o primeiro registro encontrado não é mais o usuário anônimo e sim o user@localhost, portanto a conexão será estabelecida com sucesso. Para evitar este tipo de transtorno é melhor remover o usuário anônimo após a instalação do servidor, eliminando também eventuais problemas de segurança.