Skip to main content

How to Create, Rename, and Drop a PDB in Oracle 19c

How to Create, Rename, and Drop a PDB in Oracle 19c

Introduction

This article covers manually creating a Pluggable Database (PDB) in several different ways using SQL, plus renaming and dropping a PDB once it exists.

Prerequisites

  • An RMAN backup, so you have a rollback path if anything in this article needs to be undone.
  • Free disk space, which depends on the size of the PDB you're creating or cloning.

What This Guide Covers

Jump to any section directly:

Clone the Existing PDB

Cloning creates a full, independent copy of an existing PDB, datafiles included. Here we clone a new PDB named TESTPDB from the existing ORCLPDB. The precheck below captures size, object validity, and row counts so you have a baseline to confirm the clone matches its source afterward.


Take precheck:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> select name from v$datafile where con_id=3; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/orclpdb/system01.dbf /u01/app/oracle/oradata/ORCL/orclpdb/sysaux01.dbf /u01/app/oracle/oradata/ORCL/orclpdb/undotbs01.dbf /u01/app/oracle/oradata/ORCL/orclpdb/users01.dbf /u01/app/oracle/oradata/ORCL/orclpdb/users02.dbf /u01/app/oracle/oradata/ORCL/orclpdb/OGGPDB01.dbf /u01/app/oracle/oradata/ORCL/orclpdb/audit_data01.dbf 7 rows selected. SQL> select name from v$tempfile where con_id=3; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/orclpdb/temp01.dbf SQL> alter session set container=ORCLPDB; Session altered. SQL> select sum(BYTES)/1024/1024/1024 as "Size(GB)" from dba_data_files; Size(GB) ---------- 2.43359375 SQL> select sum(BYTES)/1024/1024/1024 as "Size(GB)" from dba_segments; Size(GB) ---------- 1.11358643 SQL> select status,count(*) from dba_objects group by status; STATUS COUNT(*) ------- ---------- VALID 73176 INVALID 12 SQL> select USERNAME,ACCOUNT_STATUS,EXPIRY_DATE,PROFILE from dba_users where oracle_maintained='N'; USERNAME ACCOUNT_STATUS EXPIRY_DA PROFILE ------------------------------ -------------------------------- --------- -------------------- PDBADMIN OPEN 21-JUL-25 DEFAULT C##CLONE OPEN DEFAULT CDBTEST OPEN DEFAULT TESTAUDIT OPEN 19-FEB-26 DEFAULT C##TEST OPEN DEFAULT TEST OPEN 26-NOV-25 DEFAULT C##OGG OPEN DEFAULT OGG OPEN 29-NOV-25 DEFAULT 8 rows selected. SQL> select count(*) from test.COMPANY; COUNT(*) ---------- 7 Create directory for PDB datafiles:
[oracle@orcl ~]$ mkdir -p /u01/app/oracle/oradata/ORCL/testpdb Clone the PDB:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> CREATE PLUGGABLE DATABASE TESTPDB from ORCLPDB FILE_NAME_CONVERT=('/u01/app/oracle/oradata/ORCL/orclpdb','/u01/app/oracle/oradata/ORCL/testpdb'); Pluggable database created. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB MOUNTED SQL> alter PLUGGABLE DATABASE TESTPDB open; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO Take postcheck:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO SQL> set lines 333 pages 333 SQL> col name for a50 SQL> select name from v$datafile where con_id=4; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/testpdb/system01.dbf /u01/app/oracle/oradata/ORCL/testpdb/sysaux01.dbf /u01/app/oracle/oradata/ORCL/testpdb/undotbs01.dbf /u01/app/oracle/oradata/ORCL/testpdb/users01.dbf /u01/app/oracle/oradata/ORCL/testpdb/users02.dbf /u01/app/oracle/oradata/ORCL/testpdb/OGGPDB01.dbf /u01/app/oracle/oradata/ORCL/testpdb/audit_data01.dbf 7 rows selected. SQL> select name from v$tempfile where con_id=4; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/testpdb/temp01.dbf SQL> alter session set container=TESTPDB; Session altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 4 TESTPDB READ WRITE NO SQL> select sum(BYTES)/1024/1024/1024 as "Size(GB)" from dba_data_files; Size(GB) ---------- 2.43359375 SQL> select sum(BYTES)/1024/1024/1024 as "Size(GB)" from dba_segments; Size(GB) ---------- 1.11358643 SQL> select status,count(*) from dba_objects group by status; STATUS COUNT(*) ------- ---------- VALID 73263 INVALID 12 SQL> select USERNAME,ACCOUNT_STATUS,EXPIRY_DATE,PROFILE from dba_users where oracle_maintained='N'; USERNAME ACCOUNT_STATUS EXPIRY_DA PROFILE ------------------------------ -------------------------------- --------- -------------------- PDBADMIN OPEN 21-JUL-25 DEFAULT C##CLONE OPEN DEFAULT CDBTEST OPEN DEFAULT TESTAUDIT OPEN 19-FEB-26 DEFAULT C##TEST OPEN DEFAULT TEST OPEN 26-NOV-25 DEFAULT C##OGG OPEN DEFAULT OGG OPEN 29-NOV-25 DEFAULT 8 rows selected. SQL> select count(*) from test.COMPANY; COUNT(*) ---------- 7

The matching row counts and object-status figures between the precheck and postcheck confirm TESTPDB is a faithful copy of ORCLPDB — same data, same schema state, just under a new PDB name and its own datafiles.

Blank PDB Creation

Unlike cloning, a blank PDB starts empty and is created from the PDB$SEED template rather than copying an existing PDB's data.

 
Create directory for PDB datafiles.
[oracle@orcl ~]$ mkdir -p /u01/app/oracle/oradata/ORCL/testpdb2 Create blank PDB:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO SQL> SQL> CREATE PLUGGABLE DATABASE TESTPDB2 ADMIN USER pdb_admin IDENTIFIED BY YourP@ssw0rd FILE_NAME_CONVERT=('/u01/app/oracle/oradata/ORCL/pdbseed','/u01/app/oracle/oradata/ORCL/testpdb2'); Pluggable database created. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO 5 TESTPDB2 MOUNTED SQL> SQL> ALTER PLUGGABLE DATABASE testpdb2 OPEN; Warning: PDB altered with errors. Check PDB violations:
SQL> set lines 333 pages 333 SQL> col NAME for a20 SQL> col CAUSE for a30 SQL> col MESSAGE for a70 SQL> select name,cause,type,message,status,action from PDB_PLUG_IN_VIOLATIONS where name='PROD'; NAME CAUSE TYPE MESSAGE STATUS --------- ------------- ------ ----------------------------------------------------------------------------- --------- TESTPDB2 Sync Failure ERROR Sync PDB failed with ORA-959 during 'alter user c##ogg quota unlimited on OGG'. PENDING We need to create one tablespace OGG for user c##ogg as this database is being used for Golden Gate. Then try to open the PDB:
SQL> ALTER SESSION SET CONTAINER=testpdb2; Session altered. SQL> CREATE TABLESPACE ogg DATAFILE '/u01/app/oracle/oradata/ORCL/testpdb2/ogg01.dbf' SIZE 100M AUTOEXTEND ON; Tablespace created. SQL> ALTER SESSION SET CONTAINER=CDB$ROOT; Session altered. SQL> ALTER PLUGGABLE DATABASE testpdb2 close immediate; Pluggable database altered. SQL> ALTER PLUGGABLE DATABASE testpdb2 OPEN; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO 5 TESTPDB2 READ WRITE NO SQL> ALTER PLUGGABLE DATABASE testpdb2 save state; Pluggable database altered.

The ORA-959 violation here is a genuinely useful troubleshooting scenario: because PDB$SEED doesn't carry the OGG tablespace this environment's common users expect, the new PDB fails to sync until that tablespace is created inside it. Creating ogg and cycling the PDB closed and open again resolves the violation, as the final clean show pdbs confirms.

Clone the Existing PDB via Database Link

You can also clone a PDB from a different container database entirely, using a database link instead of a local source. This example clones ORCLPDB from source container ORCLDC into target container TESTDB.

Source ORCLDC
Target TESTDB

 
Create a user in source CDB database and provide the required grants:
SQL> def DEFINE _DATE = "11-AUG-25" (CHAR) DEFINE _CONNECT_IDENTIFIER = "orcldc" (CHAR) DEFINE _USER = "SYS" (CHAR) DEFINE _PRIVILEGE = "AS SYSDBA" (CHAR) DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR) DEFINE _EDITOR = "vi" (CHAR) DEFINE _O_VERSION = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.27.0.0.0" (CHAR) DEFINE _O_RELEASE = "1927000000" (CHAR) SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> CREATE USER c##clone IDENTIFIED BY YourP@ssw0rd; User created. SQL> GRANT CREATE PLUGGABLE DATABASE TO c##clone CONTAINER=ALL; Grant succeeded. Create a public database link in target with source userr & its TNS alias:
SQL> def DEFINE _DATE = "11-AUG-25" (CHAR) DEFINE _CONNECT_IDENTIFIER = "testdb" (CHAR) DEFINE _USER = "SYS" (CHAR) DEFINE _PRIVILEGE = "AS SYSDBA" (CHAR) DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR) DEFINE _EDITOR = "vi" (CHAR) DEFINE _O_VERSION = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.27.0.0.0" (CHAR) DEFINE _O_RELEASE = "1927000000" (CHAR) SQL> SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 TESTPDB READ WRITE NO SQL> create database link PDB_LINK connect to c##clone identified by YourP@ssw0rd using 'orclpdb'; Database link created. SQL> select * from dual@PDB_LINK; D - X Create directory for PDB datafiles:
[oracle@orcl ~]$ mkdir -p /u01/app/oracle/oradata/TESTDB/orclpdb Now create the PDB via database link and open it:
SQL> create pluggable database ORCLPDB from ORCLPDB@PDB_LINK file_name_convert=('/u01/app/oracle/oradata/ORCL/orclpdb','/u01/app/oracle/oradata/TESTDB/orclpdb'); Pluggable database created. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 TESTPDB READ WRITE NO 5 ORCLPDB MOUNTED SQL> alter pluggable database ORCLPDB open; Pluggable database altered. SQL> alter pluggable database ORCLPDB save state; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 TESTPDB READ WRITE NO 5 ORCLPDB READ WRITE NO

The select * from dual@PDB_LINK check matters here: it confirms the database link actually connects before you invest time in the clone itself, so a bad TNS alias or credential surfaces immediately rather than mid-clone.

Rename the PDB

There are two ways to rename a PDB, and they differ in one important respect: whether the underlying datafiles get renamed along with it.

Method 1: Renaming via global_name

This is the quicker method, but it only renames the PDB itself — the datafiles keep their original names and paths. Here TESTPDB is renamed to MYPDB.

  
Here we will rename TESTPDB to MYPDB:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO SQL> SQL> ALTER PLUGGABLE DATABASE testpdb CLOSE IMMEDIATE; Pluggable database altered. SQL> alter pluggable database TESTPDB open restricted; Pluggable database altered. SQL> select name, open_mode, restricted from v$pdbs; NAME OPEN_MODE RES -------------------- ---------- --- PDB$SEED READ ONLY NO ORCLPDB READ WRITE NO TESTPDB READ WRITE YES SQL> alter session set container=TESTPDB; Session altered. SQL> alter pluggable database rename global_name to mypdb; Pluggable database altered. SQL> select name, open_mode, restricted from v$pdbs; NAME OPEN_MODE RES -------------------- ---------- --- MYPDB READ WRITE YES SQL> ALTER PLUGGABLE DATABASE MYPDB CLOSE IMMEDIATE; Pluggable database altered. SQL> ALTER PLUGGABLE DATABASE MYPDB open; Pluggable database altered. SQL> ALTER PLUGGABLE DATABASE MYPDB save state; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 4 MYPDB READ WRITE NO SQL> SQL> conn /as sysdba Connected. SQL> SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 MYPDB READ WRITE NO SQL>

Opening the PDB in restricted mode before the rename prevents application sessions from connecting mid-change, and the brief close/open cycle afterward ensures the new name is fully in effect. Note that this method does not change the location or name of the datafiles — if you want to rename the datafiles too, use the ALTER DATABASE RENAME FILE command, or use the Unplug and Plug method below, which renames both the PDB and its datafiles in one pass.

Method 2: Unplug and Plug (Renames Datafiles Too)

This method drops the PDB from its current container and re-creates it from an XML metadata file, using FILE_NAME_CONVERT to place the datafiles under their new name at the same time.


Create directory for datafiles:
[oracle@orcl ~]$ mkdir -p /u01/app/oracle/oradata/ORCL/mypdb Fetch TESTPDB details:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO SQL> SQL> select name from v$datafile where con_id=4; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/testpdb/system01.dbf /u01/app/oracle/oradata/ORCL/testpdb/sysaux01.dbf /u01/app/oracle/oradata/ORCL/testpdb/undotbs01.dbf /u01/app/oracle/oradata/ORCL/testpdb/users01.dbf /u01/app/oracle/oradata/ORCL/testpdb/users02.dbf /u01/app/oracle/oradata/ORCL/testpdb/OGGPDB01.dbf /u01/app/oracle/oradata/ORCL/testpdb/audit_data01.dbf 7 rows selected. SQL> select name from v$tempfile where con_id=4; NAME -------------------------------------------------- /u01/app/oracle/oradata/ORCL/testpdb/temp01.dbf Unplug the PDB:
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 4 TESTPDB READ WRITE NO SQL> ALTER PLUGGABLE DATABASE TESTPDB CLOSE IMMEDIATE; Pluggable database altered. SQL> ALTER PLUGGABLE DATABASE TESTPDB UNPLUG INTO '/home/oracle/testpdb.xml'; Pluggable database altered. Drop the PDB & keep datafiles:
SQL> DROP PLUGGABLE DATABASE TESTPDB KEEP DATAFILES; Pluggable database dropped. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO Now Plug the PDB & rename datafiles:
SQL> CREATE PLUGGABLE DATABASE MYPDB USING '/home/oracle/testpdb.xml' FILE_NAME_CONVERT = ( '/u01/app/oracle/oradata/ORCL/testpdb', '/u01/app/oracle/oradata/ORCL/mypdb' ); Pluggable database created. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 6 MYPDB MOUNTED SQL> Verify the details & open the PDB:
SQL> select name from v$datafile where con_id=6; NAME ------------------------------------------------------------ /u01/app/oracle/oradata/ORCL/mypdb/system01.dbf /u01/app/oracle/oradata/ORCL/mypdb/sysaux01.dbf /u01/app/oracle/oradata/ORCL/mypdb/undotbs01.dbf /u01/app/oracle/oradata/ORCL/mypdb/users01.dbf /u01/app/oracle/oradata/ORCL/mypdb/users02.dbf /u01/app/oracle/oradata/ORCL/mypdb/OGGPDB01.dbf /u01/app/oracle/oradata/ORCL/mypdb/audit_data01.dbf 7 rows selected. SQL> select name from v$tempfile where con_id=6; NAME ------------------------------------------------------------ /u01/app/oracle/oradata/ORCL/mypdb/temp01.dbf SQL> alter pluggable DATABASE MYPDB open; Pluggable database altered. SQL> alter pluggable DATABASE MYPDB save state; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO 6 MYPDB READ WRITE NO

Comparing the datafile paths before and after — testpdb versus mypdb — confirms this method renamed both the PDB and its physical files, unlike Method 1 above. The KEEP DATAFILES option on the drop step is what preserves the files for the subsequent plug-in step; using INCLUDING DATAFILES instead would delete them.

Drop the Existing PDB

Finally, dropping a PDB permanently removes it. INCLUDING DATAFILES deletes the underlying files as well, so make sure you have the RMAN backup from the prerequisites before running this against anything other than a disposable test PDB.


SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 ORCLPDB                        READ WRITE NO
         6 MYPDB                          READ WRITE NO

SQL> ALTER PLUGGABLE DATABASE MYPDB CLOSE IMMEDIATE;

Pluggable database altered.

SQL> DROP PLUGGABLE DATABASE MYPDB INCLUDING DATAFILES;

Pluggable database dropped.

SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 ORCLPDB                        READ WRITE NO
SQL>

The PDB must be closed before it can be dropped, which is why the CLOSE IMMEDIATE step comes first. The final show pdbs confirms MYPDB is gone and only the original ORCLPDB remains.



Thank you for reading!

I hope this content has been helpful to you. Your feedback and suggestions are always welcome. Feel free to leave a comment or reach out with any queries.

Abhishek Shrivastava

Oracle DBA with hands-on experience managing production Data Guard, RAC, GoldenGate, and APEX environments. I write practical, tested installation and troubleshooting guides based on real deployment work.

📧 Email: oraeasyy@gmail.com
🌐 Website: www.oraeasy.com

Follow Us

Comments

↑