oracle 12c在cdb$root中建用户必须用c##前缀,因sql解析阶段硬编码正则^c##拦截触发ora-65096;合法路径仅两条:在pdb中建无前缀本地用户,或在cdb$root中用c##前缀加container=all建公用用户。

Oracle 12c 在 CDB$ROOT 中执行 CREATE USER 时强制要求用户名以 c## 或 C## 开头,这不是配置遗漏或权限问题,而是底层硬编码的解析规则——根本绕不过,也改不了。
ORA-65096 错误发生在 SQL 解析阶段,不是权限校验
当你在 CDB$ROOT 中运行 CREATE USER app_user IDENTIFIED BY pwd;,Oracle 还没查数据字典、没验权限、甚至没进语法树构建环节,就在解析阶段调用函数 ksuCheckCommonUserName 直接拦截。它只做一件事:检查用户名是否匹配正则 ^C##(不区分大小写,但必须是连续两个井号,且位于开头)。
以下全部无效:
-
app_user(无前缀) -
c#user(只有一个 #) -
cc##user(多了一个 c) -
"app_user"(双引号完全没用)
这个检查不读 common_user_prefix 参数,设为空、改隐藏参数、重启实例,全无效。
CONTAINER = ALL 不是“绕过开关”,而是作用域声明
显式写 CONTAINER = ALL 并不能放宽命名规则,它只是告诉 Oracle:“我要建一个跨所有 PDB 的公共用户”。而公共用户的命名规范就是硬性带 c## 前缀。
漏掉 CONTAINER = ALL 会怎样?默认按 CONTAINER = CURRENT 处理——但在 CDB$ROOT 中,CURRENT 就是 CDB$ROOT 自身,仍走公共用户校验,照样报 ORA-65096。
真正合法的两种路径:
- 在 CDB$ROOT 中建公共用户:必须
c##xxx+CONTAINER = ALL - 在某个 PDB 中建本地用户:先
ALTER SESSION SET CONTAINER = your_pdb;,再CREATE USER app_user ...(完全自由,无前缀要求)
连不上刚创建的 c## 用户?不是密码错,是连接串没配对
你用 CREATE USER c##app IDENTIFIED BY pwd; + GRANT CONNECT TO c##app; 后,执行 conn c##app/pwd@orcl 报 ORA-01017,大概率因为 orcl 是 CDB 的 service_name,而 c##app 默认无法直接登录 CDB$ROOT(除非显式授权 CREATE SESSION 给 CDB$ROOT)。
更常见也更合理的做法是:不要在 CDB$ROOT 建业务用户。切到目标 PDB 后建无前缀用户,然后在 tnsnames.ora 里为该 PDB 单独配一个 service_name(比如 hrpdb),再用 conn app/pwd@hrpdb 连。
为什么 SYS/SYSTEM 不受限制?它们是特例
SYS 和 SYSTEM 是 Oracle 内置的 common user,它们不经过 ksuCheckCommonUserName 校验。但这不构成参考依据——你建的任何非内置用户,都逃不开那条正则。
真正容易被忽略的一点:PDB 才是绝大多数应用的归属地。硬扛着在 CDB$ROOT 建 c## 用户,还要手动给每个 PDB 授权、处理连接路由、担心跨 PDB 权限扩散,远不如直接切到 PDB 建本地用户来得干净。命名自由、授权隔离、连接明确——这才是 12c 多租户设计的本意。











