When multiple workloads share a single PolarDB for PostgreSQL (Compatible with Oracle) cluster, one workload can consume disproportionate CPU or memory and starve others. Multi-tenancy lets you define resource limits at the tenant level — grouping databases, users, or individual processes under a shared CPU and memory cap — so that resource-intensive workloads cannot degrade the rest of the cluster.
Supported versions
Oracle Syntax Compatibility 2.0, minor engine version 2.0.14.12.24.0 or later.
To check your minor engine version, run SHOW polardb_version; or view the version in the console. If your cluster does not meet the version requirement, upgrade the minor engine version.
How it works
Tenant hierarchy
A tenant is a logical resource boundary within a cluster — sitting above users and databases, but below the cluster itself. Multiple users and databases can belong to a single tenant.
There are two tenant types:
| Type | Description |
|---|---|
| System tenant | A special administrative tenant. Each cluster has exactly one system tenant. It has priority access to cluster resources and can use resources from regular tenants. A user in the system tenant with cluster access permissions can access resources across all tenants. |
| Regular tenant | Resources are fully isolated from other tenants. Regular tenants must be created from within the system tenant context. |
Resource configuration
A resource configuration defines the CPU and memory limits applied to a tenant. You create a resource configuration separately, then attach it to a tenant. Detaching or deleting the tenant does not delete the resource configuration.
Resource tracking dimensions
Every session in PolarDB for PostgreSQL corresponds to a single process. Each process belongs to exactly one tenant, which prevents double-counting. The system maps processes to tenants along three dimensions:
| Dimension | Scope |
|---|---|
| Process | A single connection process initiated by a user, including any parallel query processes it spawns. System auxiliary processes are excluded. |
| User | All connection processes from the same user, including parallel query processes. System auxiliary processes are excluded. |
| Database | All connection processes accessing the same database, including parallel query processes. System auxiliary processes are excluded. |
Parallel query child processes automatically join the tenant of the session that issued the query, and are removed from the tenant when the query finishes.
System processes have no resource limits by default.
Resource limit enforcement
CPU and memory use different enforcement mechanisms:
| Resource | Enforcement | What the user sees when the limit is exceeded |
|---|---|---|
| CPU | Throttling — the cluster slows down processes to stay within the limit. | Queries run slower. |
| Memory | Eviction — sessions are terminated to release memory. Swap is disabled, so memory is a hard constraint. | Session is aborted with a memory over-limit error. |
Parameters
Parameters that require a restart take effect only after the cluster restarts. Parameters that require a RELOAD take effect after running SELECT pg_reload_conf();.
| Parameter | Description | Range | Default | When it takes effect |
|---|---|---|---|---|
polar_max_tenants | Maximum number of tenants | 0–65536 | 32 | After restart |
polar_resource_manager.enable_resource_manager | Enables the Resource Manager process for memory limiting and out-of-memory (OOM) prevention | on/off | on | After restart |
polar_resource_manager.database_name | Database that stores tenant metadata | — | polardb_admin | After restart |
polar_resource_manager.stat_interval | Data collection interval | 10–10000 ms | 500 ms | After RELOAD |
polar_resource_manager.total_mem_request_rate | Active eviction threshold | 50%–100% | 80% | After RELOAD |
polar_resource_manager.total_mem_limit_rate | Forced eviction threshold | 50%–100% | 95% | After RELOAD |
polar_resource_manager.total_mem_limit_remain_size | Reserved memory | 131072–INT_MAX KB | 256000 KB | After RELOAD |
polar_resource_manager.enable_log | Enables log records | ON/OFF | ON | After RELOAD |
Set up multi-tenancy
Before you begin
A PolarDB for PostgreSQL (Compatible with Oracle) cluster running Oracle Syntax Compatibility 2.0, minor engine version 2.0.14.12.24.0 or later
Step 1: Install the extension
Install the polar_resource_manager extension in the database specified by polar_resource_manager.database_name (default: polardb_admin):
CREATE EXTENSION polar_resource_manager;If you change the value of polar_resource_manager.database_name, all existing multi-tenancy configuration becomes invalid.
Step 2: Create a resource configuration
SELECT polar_resource_manager.polar_create_resource_config('resource_config_name');resource_config_name follows database object naming rules. Names longer than 64 bytes are truncated automatically.
Step 3: Set resource limits
Set the CPU limit (in cores) and the memory limit (in bytes) on the resource configuration:
-- Set CPU limit: 0.3 = 30% of one CPU core; 2 = two full CPU cores
SELECT polar_resource_manager.polar_alter_resource_config('resource_config_name', 'cpu_rate_limit', 2);
-- Set memory limit in bytes
SELECT polar_resource_manager.polar_alter_resource_config('resource_config_name', 'mem_limit', value);cpu_rate_limit is measured in cores (float). A value of 0.3 limits usage to 30% of one core; a value of 2 allows up to two full cores. The sum of cpu_rate_limit values across all tenants can exceed the cluster's total physical CPU capacity — the system throttles processes when individual limits are reached.
mem_limit is in bytes. For enforcement behavior when a tenant exceeds its memory limit, see Memory resource management.
Step 4: Create a tenant
A resource configuration must exist before you create a tenant.
SELECT polar_resource_manager.polar_create_tenant('tenant_name', 'resource_config_name');tenant_name follows database object naming rules. Names longer than 64 bytes are truncated automatically.
To modify an existing tenant:
-- Rename the tenant
SELECT polar_resource_manager.polar_alter_tenant('tenant_name', 'name', 'new_tenant_name');
-- Switch the resource configuration
SELECT polar_resource_manager.polar_alter_tenant('tenant_name', 'resource_config', 'new_resource_config_name');To delete a tenant (this does not delete the attached resource configuration):
SELECT polar_resource_manager.polar_drop_tenant('tenant_name');To delete a resource configuration:
SELECT polar_resource_manager.polar_drop_resource_config('resource_config_name');Step 5: Assign databases, users, or processes
Assign at least one database, user, or process to the tenant so that sessions are tracked against its resource limits.
Assign a database
A database can belong to only one tenant. Assigning it to another tenant fails.
SELECT polar_resource_manager.polar_tenant_add_database('tenant_name', 'database_name');To view current database-to-tenant assignments:
SELECT dbsname, tenantname FROM polar_resource_manager.polar_tenants_dbs;Assign a user
A user can belong to only one tenant. Assigning them to another tenant fails.
SELECT polar_resource_manager.polar_tenant_add_user('tenant_name', 'user_name');To view current user-to-tenant assignments:
SELECT username, tenantname FROM polar_resource_manager.polar_tenants_users;Assign a process
A process can belong to only one tenant. If you assign a process to multiple tenants, only the last assignment takes effect.
SELECT polar_resource_manager.polar_tenant_add_process('tenant_name', pid);Step 6: View resource usage
Query the polar_all_resource_configs_detail view for a snapshot of all tenants' resource usage:
SELECT * FROM polar_resource_manager.polar_all_resource_configs_detail;| Column | Type | Description |
|---|---|---|
tenantname | NAME | Tenant name |
resource_config_name | NAME | Resource configuration name |
num_processes | INTEGER | Total number of processes |
num_idle_processes | INTEGER | Number of idle processes |
num_active_processes | INTEGER | Number of active processes |
cpu_rate_limit | DOUBLE PRECISION | CPU limit for the tenant (in cores) |
per_process_cpu_rate_limit | DOUBLE PRECISION | CPU limit per process |
mem_limit | DOUBLE PRECISION | Memory limit (in bytes) |
mem_usage | DOUBLE PRECISION | Current memory usage |
idle_processes_mem_usage | DOUBLE PRECISION | Memory used by idle processes |
active_processes_mem_usage | DOUBLE PRECISION | Memory used by active processes |
cpu_usage_rate | DOUBLE PRECISION | Current CPU usage rate |
CPU resource management
When a tenant's CPU usage exceeds cpu_rate_limit, the cluster throttles the corresponding processes to enforce the limit.
cpu_rate_limit is measured in CPU cores (float). The sum of cpu_rate_limit values across all tenants can exceed the cluster's physical CPU capacity — this is intentional, since not all tenants are active simultaneously.
When a parallel query is running, its backend child processes join the tenant of the initiating session. When the query finishes, those child processes are removed from the tenant.
Memory resource management
Because swap is disabled, memory is a hard resource. Instead of throttling, PolarDB for PostgreSQL handles memory over-limits through tenant-level eviction — similar to OS-level out-of-memory (OOM) handling, but scoped to individual tenants rather than the entire database.
When memory usage is high, two eviction policies apply:
Active eviction (threshold: total_mem_request_rate, default 80%)
When total cluster memory usage exceeds 80%, the system checks each tenant. If a tenant's memory usage exceeds its mem_limit, the system terminates sessions in that tenant to bring usage down. This continues until total memory falls below the threshold.
Forced eviction (threshold: total_mem_limit_rate, default 95%)
When total cluster memory exceeds 95%, the system traverses all processes and terminates sessions regardless of individual tenant limits. This is a last-resort measure to prevent a cluster-wide OOM condition.
In both cases, the user receives a memory over-limit error. The eviction is triggered by sending a SIGUSR2 signal to the session process.
Parallel queries: If a parallel query's backend process exceeds the memory limit, the corresponding user session is aborted — not just the backend process.
System processes: System background processes belong to the system tenant and are not subject to active eviction.