Pular para o conteúdo
Health Check gratuito
Fundamentos

Criar usuário Oracle: CDB, PDB e non-CDB sem erro

Antes do CREATE USER no Oracle 19c, três perguntas definem tudo. Veja o ORA-01045, a diferença entre usuário comum (C##) e local, e o privilégio mínimo.

7 min de leitura testado em Oracle 19c
Um cubo de vidro central ligado por linhas de luz azul a três cubos menores, um deles com a borda acesa em vermelho, sobre fundo navy

O pedido costuma chegar curto: "cria um usuário para a aplicação nova". O CREATE USER em si cabe em três linhas e qualquer DBA júnior escreve de cabeça. O que complica vem depois, quando o usuário não consegue conectar, ou conecta onde não devia, ou existe no root de um multitenant e ninguém sabe explicar por quê.

Criar usuário no Oracle é simples. Criar certo depende de contexto, e o contexto cabe em três perguntas que eu respondo antes de digitar qualquer comando.

As três perguntas antes do CREATE USER

  1. O ambiente é CDB ou non-CDB?
  2. Onde o usuário vai ter acesso: uma PDB, várias, todas, ou um banco tradicional?
  3. Quais privilégios ele precisa?

A primeira muda o comando. Num CDB, o lugar onde você está conectado define que tipo de usuário nasce. Num non-CDB (a arquitetura tradicional, que existia antes do 12c) não há essa escolha, e o comportamento é o mesmo de criar o usuário dentro de uma PDB.

A segunda define o escopo: um usuário que só precisa de uma PDB não deveria existir nas outras.

A terceira é a que mais dá trabalho, porque quem pede o acesso muitas vezes não sabe dizer o que precisa. Cabe ao DBA conversar até chegar no privilégio mínimo, e começar sempre do menor conjunto possível.

Criando o usuário em um non-CDB

No lab, o banco ORCL é non-CDB. Conectado como SYS:

create user app1 identified by oracle
  default tablespace users
  temporary tablespace temp;

A senha aí é a do laboratório. Em ambiente real, use uma senha gerada e entregue por um canal adequado.

Para conferir que o usuário existe:

set lines 200
set pages 200
col username format a20
col account_status format a20

select username as username,
       account_status as account_status
  from dba_users
 where username = 'APP1';

O status vem como OPEN, o que dá a impressão de que o usuário está pronto. Não está. Saia do SQL*Plus e tente conectar com ele:

$ sqlplus app1/oracle
ORA-01045: user APP1 lacks CREATE SESSION privilege; logon denied

Esse é o comportamento padrão: um usuário recém-criado não tem privilégio nenhum, nem o de abrir uma sessão. O mínimo para ele conectar é o CREATE SESSION:

grant create session to app1;

Agora a conexão funciona, e dá para ver exatamente o que a sessão carrega:

show user

select privilege as privilege
  from session_privs;

A SESSION_PRIVS lista os privilégios ativos na sessão atual. Para o APP1 aparece só o CREATE SESSION, e é isso que eu quero ver num usuário de aplicação recém-entregue. Tudo que vier além disso precisa de uma razão.

O roteiro completo com todos os comandos deste artigo está em https://mrdba.com.br/labs/criar-usuarios-oracle?utm_source=blog&utm_medium=artigo&utm_campaign=criar-usuarios-oracle. Dá para rodar do começo ao fim na sua própria máquina.

Usuário comum no CDB: o prefixo C## e o CONTAINER = ALL

Num CDB existem dois tipos de usuário, e a diferença é de escopo. O usuário comum é criado no CDB$ROOT e existe no root e em todas as PDBs. O nome precisa começar com C##.

No lab, o CDB1 tem as PDBs HUMAN_RESOURCES e CUSTOMER_ORDERS. Antes de criar um usuário comum, confira o estado delas:

show pdbs

Se alguma estiver MOUNTED, abra antes com alter pluggable database <nome> open;. Assim o usuário comum aparece em todas as PDBs já na consulta de conferência logo abaixo (uma PDB fechada só recebe o usuário quando for aberta).

Conectado no CDB$ROOT:

create user c##app identified by oracle container = all;
grant create session to c##app container = all;
grant set container to c##app container = all;

O container = all aparece nas três linhas por um motivo. Na criação, diz que o usuário vale para todos os containers. Nos grants, diz que o privilégio também vale em todos. Sem ele no grant, o usuário comum existiria nas PDBs mas só poderia conectar no root.

A cláusula CONTAINER só aceita ALL ou CURRENT. Não existe uma forma de dizer "este usuário comum em duas das cinco PDBs". Se o escopo é parcial, a resposta é outra: usuário local, que vem na próxima seção.

Sobre o grant set container: ele serve para trocar de container dentro da sessão, com alter session set container = <pdb>. Conectar direto numa PDB pelo serviço dela já funciona só com o CREATE SESSION concedido com container = all. Conceda o SET CONTAINER só quando o usuário realmente precisa navegar entre PDBs.

Para confirmar onde o usuário existe:

col common format a6
col name format a20

select b.name as pdb,
       a.username as username,
       a.common as common
  from cdb_users a, v$pdbs b
 where a.con_id = b.con_id
   and a.username like 'C##APP'
 order by b.name;

A CDB_USERS enxerga todos os containers de uma vez, e o join com V$PDBS traz o nome de cada PDB. O resultado é uma linha por PDB, com COMMON igual a YES. Sem o join, aparece também a linha do root (CON_ID 1).

Usuário local: criado dentro da PDB, sem prefixo

O usuário local pertence a uma única PDB. Não leva prefixo e se comporta igual a um usuário de non-CDB, porque do ponto de vista da PDB ela é um banco completo.

Para criar o mesmo usuário em duas PDBs, entre em cada uma:

alter session set container = HUMAN_RESOURCES;
create user app_local identified by oracle;

alter session set container = CUSTOMER_ORDERS;
create user app_local identified by oracle;

Antes de cada CREATE USER, show con_name confirma em qual container você está. Eu rodo esse comando por hábito, para não criar o usuário na PDB errada.

Os dois APP_LOCAL têm o mesmo nome e a mesma senha, mas são dois usuários diferentes. Cada um vive no dicionário da sua PDB, com seus próprios privilégios e objetos. Dropar um não afeta o outro.

O usuário local também nasce sem CREATE SESSION, então cai no mesmo ORA-01045 até receber o grant dentro da PDB.

Usuário comum Usuário local
Onde é criado CDB$ROOT Dentro da PDB
Prefixo C## obrigatório Sem prefixo
Onde existe Root e todas as PDBs Só na PDB onde foi criado
Cláusula CONTAINER = ALL CONTAINER = CURRENT (padrão)

Por que o prefixo C## existe

O prefixo existe para evitar conflito de nomes entre o root e as PDBs. Imagine que o root aceitasse um usuário comum chamado APP e, em paralelo, alguém criasse um usuário local APP dentro de uma PDB. Na hora de propagar o comum para aquela PDB, o nome já estaria ocupado.

Com a regra do C##, os dois espaços de nomes ficam separados. O root só aceita nomes com C## para usuários comuns, e uma PDB não aceita C## para usuários locais. Se você tentar criar APP direto no root, o Oracle recusa com ORA-65096. Se tentar criar C##APP dentro da PDB, recusa também.

Consultando os usuários no dia a dia

DBA_USERS mostra os usuários do container em que você está conectado, e CDB_USERS, consultada no root, mostra todos os containers. Eu guardo uma consulta sobre a DBA_USERS num script no SQLPATH, que filtra por parte do nome e traz criação, profile, status, tablespaces e as colunas COMMON e ORACLE_MAINTAINED. A segunda ajuda a separar o que você criou do que o Oracle trouxe na instalação. O script completo está no lab.

Boas práticas para criar usuário no Oracle

Defina o escopo antes de criar. Se a pessoa precisa de acesso somente na CUSTOMER_ORDERS, crie um usuário local nessa PDB e pare aí. Um usuário comum com CONTAINER = ALL é a escolha certa para quem administra o CDB inteiro, e é exagero para uma aplicação que vive numa PDB só.

Conceda só o CREATE SESSION no começo e acrescente o resto conforme o uso aparecer. Na prática o conjunto mínimo costuma crescer, mas é bem mais fácil justificar um privilégio adicionado do que descobrir depois por que um usuário de relatório podia alterar tabelas.

Quando o ambiente for multitenant, confirme o container antes do comando. O mesmo CREATE USER, rodado no root ou dentro de uma PDB, produz usuários de tipos diferentes.

Se você quer montar a base de conhecimento por trás de decisões como essa, o e-book Raízes de um DBA organiza o caminho: https://mrdba.com.br/roteiro-dba.

Marcio Mandarino é DBA Oracle e SQL Server há mais de 20 anos, com passagens por ambientes críticos de varejo, saúde, educação e locação de equipamentos.

O script deste laboratório Baixe o SQL usado aqui e rode no seu ambiente.
Baixar o SQL
Marcio Mandarino

Marcio Mandarino

DBA Oracle e SQL Server há mais de 20 anos. Atendo plantão, recuperação de incidente e gestão contínua de bancos de dados. Este artigo saiu de um laboratório que rodou antes de virar texto.

Continue lendo

Quer ser DBA? Comece pelas raízes.

O e-book gratuito Raízes de um DBA mostra o que estudar, em que ordem e por quê, com a base de TI e o Oracle crescendo juntos.

Quero o e-book grátis