AWS Organizations' RCP Quota Has Doubled, So I Checked the 2,000 Limit
This page has been translated by machine translation. View original
Introduction
On July 22, 2026, the per-organization limit for AWS Organizations resource control policies (RCPs) was raised from 1,000 to 2,000.
| Item | Before | After |
|---|---|---|
| RCP limit (per organization) | 1,000 | 2,000 |
These are the quotas and API rate limits related to RCPs.
| Item | Value |
|---|---|
| RCP policy size limit | 5,120 characters |
| RCP attachment limit (each for root/OU/account) | 5 (including RCPFullAWSAccess) |
| CreatePolicy/DeletePolicy/AttachPolicy/DetachPolicy | rate 2/sec, burst 3 |
Details of each quota are summarized in the documentation.
Verification Details
Verification Environment
| Item | Value |
|---|---|
| Executed from | Test Organization management account |
| Region | us-east-1 (Organizations API endpoint) |
| CLI | AWS CLI v2 (latest) |
| RCP policy type | Enabled |
| Test Organization | All features enabled, isolated environment |
Preliminary Check
At the start of the verification, the only existing RCP was the AWS managed policy RCPFullAWSAccess. The RCPs I created were not attached anywhere.
Contents of the Policy to Create
For the 2,000 RCPs I created, I used the following minimal Deny statement. It specifies the nonexistent region xx-nonexistent-1 as the condition, so it is safe content that would not affect actual operations even if attached by accident.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonexistentRegionNoOp",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "xx-nonexistent-1"
}
}
}
]
}
Creating 2,000 RCPs
Considering the CreatePolicy rate limit (rate 2/sec, burst 3), I attempted to create 2,001 policies with a script that incorporates a 0.5-second sleep per policy and exponential backoff (up to 30 seconds) on ThrottlingException.
Full creation script
#!/usr/bin/env bash
# RCP 2,001件作成スクリプト(2,000件目まで成功→2,001件目でクォータエラーを期待)
set -uo pipefail
ARTICLE_DIR="/path/to/article"
POLICY_CONTENT="$ARTICLE_DIR/logs/rcp-policy-content.json"
RAW_DIR="$ARTICLE_DIR/logs/raw"
MILESTONE_LOG="$ARTICLE_DIR/logs/raw/milestones.log"
SUMMARY_LOG="$ARTICLE_DIR/logs/raw/create-loop-summary.tsv"
TOTAL=2001
START_INDEX=1
REGION="us-east-1"
echo -e "index\thttp_status_or_error\telapsed_ms\tpolicy_id\tthrottled_retries" > "$SUMMARY_LOG"
: > "$MILESTONE_LOG"
start_all=$(date +%s.%N)
throttle_count=0
for i in $(seq $START_INDEX $TOTAL); do
name="rcp-quota-test-$(printf '%04d' "$i")"
backoff=1
retries=0
t0=$(date +%s.%N)
while true; do
out=$(aws organizations create-policy \
--name "$name" \
--description "RCP quota test policy #$i" \
--type RESOURCE_CONTROL_POLICY \
--content "file://$POLICY_CONTENT" \
--region "$REGION" \
--output json 2>&1)
rc=$?
if [ $rc -eq 0 ]; then
break
fi
if echo "$out" | grep -q "ThrottlingException\|TooManyRequestsException"; then
throttle_count=$((throttle_count+1))
retries=$((retries+1))
sleep "$backoff"
backoff=$((backoff * 2))
if [ $backoff -gt 30 ]; then backoff=30; fi
continue
else
# 別のエラー(クォータ超過等)→ ループを抜けて記録
break
fi
done
t1=$(date +%s.%N)
elapsed_ms=$(awk "BEGIN {printf \"%.0f\", ($t1 - $t0) * 1000}")
if [ $rc -eq 0 ]; then
policy_id=$(echo "$out" | grep -o '"Id": "p-[^"]*"' | head -1 | sed 's/"Id": "//;s/"//')
echo -e "${i}\tSUCCESS\t${elapsed_ms}\t${policy_id}\t${retries}" >> "$SUMMARY_LOG"
echo "$out" > "$RAW_DIR/create-$(printf '%04d' "$i").json"
else
echo -e "${i}\tERROR\t${elapsed_ms}\t-\t${retries}" >> "$SUMMARY_LOG"
echo "$out" > "$RAW_DIR/create-$(printf '%04d' "$i")-error.json"
echo "[$i] ERROR: $out" >> "$MILESTONE_LOG"
fi
if [ "$i" -eq 1000 ]; then
echo "[MILESTONE] 1000件目 index=$i rc=$rc elapsed_ms=$elapsed_ms" >> "$MILESTONE_LOG"
fi
if [ "$i" -eq 1001 ]; then
echo "[MILESTONE] 1001件目(旧上限突破) index=$i rc=$rc elapsed_ms=$elapsed_ms" >> "$MILESTONE_LOG"
fi
if [ "$i" -eq 2000 ]; then
echo "[MILESTONE] 2000件目(新上限到達) index=$i rc=$rc elapsed_ms=$elapsed_ms" >> "$MILESTONE_LOG"
fi
if [ "$i" -eq 2001 ]; then
echo "[MILESTONE] 2001件目(想定エラー) index=$i rc=$rc elapsed_ms=$elapsed_ms" >> "$MILESTONE_LOG"
fi
# rate 2/秒, burst 3 を踏まえた基本スリープ
sleep 0.5
done
end_all=$(date +%s.%N)
total_elapsed=$(awk "BEGIN {printf \"%.1f\", ($end_all - $start_all)}")
echo "[SUMMARY] total_elapsed_sec=$total_elapsed throttle_count=$throttle_count" >> "$MILESTONE_LOG"
echo "DONE total_elapsed_sec=$total_elapsed throttle_count=$throttle_count"
| Milestone | index | Result | elapsed_ms |
|---|---|---|---|
| 1,000th created | 1000 | Success | 1187 |
| 1,001st created (exceeded old limit of 1,000) | 1001 | Success | 1158 |
| 2,000th created (reached new limit) | 2000 | Success | 1149 |
| 2,001st created (expected error) | 2001 | Failure | 1047 |
In this verification environment, I did not submit any individual quota increase request. Since I was able to create more than 1,000 without a request and succeeded up to the 2,000th, I confirmed that the new limit is in effect in this verification environment.
Checking the Error on the 2,001st
The following error was returned for the 2,001st policy.
An error occurred (ConstraintViolationException) when calling the CreatePolicy operation:
You have exceeded the allowed number of policies.
Additional error details:
Reason: POLICY_NUMBER_LIMIT_EXCEEDED
Since the creation of the 2,000th succeeded and this error was returned on the 2,001st, we can confirm that the limit for custom RCPs per organization is 2,000.
At this point, the total count from list-policies --filter RESOURCE_CONTROL_POLICY was 2,000 custom RCPs + 1 AWS managed policy (RCPFullAWSAccess) = 2,001 in total. From this result, we can conclude that RCPFullAWSAccess is not counted toward the creation limit of 2,000 per organization.
Measured Throttling
The measured values are as follows.
| Item | Value |
|---|---|
| Number of throttling occurrences | 0 |
| Average response time per policy | Approx. 1.1–1.2 seconds |
| Sleep in loop | Fixed at 0.5 sec per policy (no backoff triggered) |
| Total time (2,001 attempts) | 3,314.1 seconds (approx. 55 min 14 sec) |
| Effective throughput | Approx. 0.60 policies/sec |
This time, with sequential execution the API response took about 1.1 seconds, and adding the fixed 0.5-second sleep made the actual request interval about 1.6 seconds. Under these conditions, no throttling occurred. The time required for bulk creation can be estimated as (API latency + sleep) × count.
Cleanup
After the verification was complete, I deleted all 2,000 RCPs I created (excluding RCPFullAWSAccess).
Summary
With the RCP limit expanded to 2,000, there is more room to design finer-grained guardrails per OU, account, and protected resource.
However, if you increase the number of policies up to the limit, the time required for maintenance and updates cannot be ignored. In this verification, sequential creation ran at about 0.60 policies/sec, so processing on the scale of 2,000 policies does not finish in a short time. Likewise for update processing, an execution plan that takes into account API response times and the Organizations API rate limits is necessary.
This article did not verify performance or throttling behavior at higher parallelism. Therefore, when starting a design premised on the 2,000 limit, it would be wise to evaluate in advance not only the number of policies but also how long it would take to update all of them, make staged changes, and apply emergency fixes.
Although the limit on the number of RCP policies has increased, rather than consolidating all controls into RCPs, please consider combining them appropriately, including SCPs, according to each one's purpose, update frequency, and management cost.

