c##sys不是合法的公共用户名,因sys是oracle系统保留字,命名校验在sql解析阶段直接拦截,即使加container=all也无效;正确做法是创建合规名如c##admin并显式授予sysdba container=all。

C##SYS不是合法的公共用户名
Oracle强制要求公共用户必须以C##或c##开头,但C##SYS是保留名称,系统直接拒绝创建。执行CREATE USER C##SYS IDENTIFIED BY ... CONTAINER=ALL会报ORA-65108: invalid common user or role name。这不是权限问题,是命名校验在语法解析阶段就拦截了。
常见误操作包括:
- 复制ROOT中
SYS的命名习惯,直接套用C##SYS - 在脚本中硬编码用户名,未检查是否命中保留字列表(如
SYS、SYSTEM、OUTLN、DVSYS等) - 依赖文档里“C##开头即公共用户”的简化描述,忽略保留字例外规则
CONTAINER=ALL不能绕过保留字检查
即使显式加上CONTAINER=ALL,也不会改变校验顺序——Oracle先验用户名合法性,再处理容器语义。所以CREATE USER C##SYS IDENTIFIED BY pwd CONTAINER=ALL和CREATE USER C##SYS IDENTIFIED BY pwd报的都是同一个错误。
验证方式:
- 查保留字:
SELECT * FROM V$RESERVED_WORDS WHERE KEYWORD = 'SYS';(返回非空即被保留) - 查已存在公共用户:
SELECT USERNAME, COMMON FROM CDB_USERS WHERE USERNAME LIKE 'C##%' AND COMMON = 'YES';,你会发现没有C##SYS
真正需要等效权限时该怎么做
如果目标是在所有PDB中拥有类似SYS的权限,正确路径是:
- 创建合规名称的公共用户,例如
C##ADMIN或C##DBA - 在
CDB$ROOT中授予GRANT SYSDBA TO C##ADMIN CONTAINER=ALL(注意:SYSDBA本身是系统特权,不是角色,必须用GRANT ... TO ... CONTAINER=ALL) - 确认该用户能跨容器登录:
sqlplus C##ADMIN/pwd@pdb_name as sysdba
关键点:公共用户的SYSDBA权限必须显式授予且带CONTAINER=ALL,否则只在当前容器生效;而SYS账号本身是CDB内置账户,不走公共用户机制,不可复制。
多租户环境下最易被忽略的是:保留字校验发生在CDB层,与你当前连接的是ROOT还是PDB无关——哪怕你在某个PDB里执行,C##SYS依然非法。











