diff --git a/apps/docs/content/guides/api/rest/postgrest-error-codes.mdx b/apps/docs/content/guides/api/rest/postgrest-error-codes.mdx
index 19288d73d08..8c91fbe3694 100644
--- a/apps/docs/content/guides/api/rest/postgrest-error-codes.mdx
+++ b/apps/docs/content/guides/api/rest/postgrest-error-codes.mdx
@@ -67,6 +67,19 @@ Here's the text formatted as a proper markdown table:
| 42501 | if authenticated 403, else 401 | insufficient privileges |
| other | 400 | |
+
+
+Some codes in this table are triggered by platform conditions rather than application code. Seeing them in high volume usually points to an infrastructure event rather than a bug in your queries:
+
+- **25006** — The database has entered read-only mode due to disk quota. See [Read-only mode](/docs/guides/platform/database-size#read-only-mode) for causes and recovery steps.
+- **53100** — Disk is full. Supabase emits this alongside 25006 during severe disk exhaustion.
+- **53300** — Too many connections. The connection pool has reached its limit; check your [connection pool settings](/docs/guides/database/connection-management).
+- **57P03** — The database cannot accept connections, typically during a restart or failover.
+
+When you see these codes in volume, check the [Database dashboard](/dashboard/project/_/observability/database) before debugging application code.
+
+
+
## API level errors
### Connection errors
diff --git a/apps/docs/content/guides/observability/advanced-log-filtering.mdx b/apps/docs/content/guides/observability/advanced-log-filtering.mdx
index fc46a5c8b22..ecf286ca5d4 100644
--- a/apps/docs/content/guides/observability/advanced-log-filtering.mdx
+++ b/apps/docs/content/guides/observability/advanced-log-filtering.mdx
@@ -95,6 +95,41 @@ limit 100;
Combine predicates with `and`, `or`, and `not`. Select only the fields needed for the investigation. To correlate sources, use an identifier present in both; a shared timestamp alone does not establish that events belong to the same request.
+## Filter by Postgres error code [#sqlstate-filtering]
+
+Filter `postgres_logs` by SQLSTATE to surface errors at a specific category rather than by message text. The code lives in `log_attributes['parsed.sql_state_code']`.
+
+To see which error codes are occurring across a time window:
+
+```sql
+select
+ log_attributes['parsed.sql_state_code'] as sqlstate,
+ count() as occurrences
+from logs
+where source = 'postgres_logs'
+ and log_attributes['parsed.sql_state_code'] != ''
+group by sqlstate
+order by occurrences desc
+limit 50;
+```
+
+During a platform-level incident (such as the database entering read-only mode), codes like `25006` (`read_only_sql_transaction`) and `53100` (`disk_full`) will dominate the results. To focus on application errors while a platform incident is active, exclude the known platform codes:
+
+```sql
+select
+ timestamp,
+ log_attributes['parsed.sql_state_code'] as sqlstate,
+ event_message
+from logs
+where source = 'postgres_logs'
+ and log_attributes['parsed.sql_state_code'] not in ('25006', '53100', '57P03')
+ and log_attributes['parsed.error_severity'] = 'ERROR'
+order by timestamp desc
+limit 50;
+```
+
+SQLSTATE codes starting with `25` or `53` usually indicate platform-level resource events rather than application bugs. See the [PostgREST error codes reference](/docs/guides/api/rest/postgrest-error-codes#database-level-errors) and [Database size guide](/docs/guides/platform/database-size#read-only-mode) for context.
+
## Query limits [#limit-and-result-row-limitations]
Use an explicit `limit` and narrow time range. The logs query surface rejects `select *` and `count(*)`; list columns and use `count()`. A result limit bounds returned rows, not the time range scanned.
diff --git a/apps/docs/content/guides/platform/database-size.mdx b/apps/docs/content/guides/platform/database-size.mdx
index bf8532ebd3d..65466517d3e 100644
--- a/apps/docs/content/guides/platform/database-size.mdx
+++ b/apps/docs/content/guides/platform/database-size.mdx
@@ -124,7 +124,24 @@ To resolve it, upgrade your plan or disable your Spend Cap to lift the restricti
In some cases Supabase may put your database into read-only mode to prevent your database from exceeding the billing or disk limitations.
-In read-only mode, clients will encounter errors such as `cannot execute INSERT in a read-only transaction`. Regular operation (read-write mode) is automatically re-enabled once usage is below 95% of the disk size,
+In read-only mode, clients will encounter errors such as `cannot execute INSERT in a read-only transaction`. The Postgres SQLSTATE code for this error is **25006** (`read_only_sql_transaction`). During severe disk exhaustion, **SQLSTATE 53100** (`disk_full`) may also appear. Regular operation (read-write mode) is automatically re-enabled once usage is below 95% of the disk size.
+
+While in read-only mode, all write operations are blocked — including background jobs, scheduled tasks, and internal monitoring writes. Data that those jobs write (such as disk usage snapshots) will be stale until the database returns to read-write mode.
+
+To confirm that your database has entered read-only mode, query Postgres logs for the relevant SQLSTATE codes using the [Logs Explorer](/dashboard/project/_/logs/explorer) with the query source set to **Logs**:
+
+```sql
+select
+ timestamp,
+ log_attributes['parsed.error_severity'] as severity,
+ log_attributes['parsed.sql_state_code'] as sqlstate,
+ event_message
+from logs
+where source = 'postgres_logs'
+ and log_attributes['parsed.sql_state_code'] in ('25006', '53100', '57P03')
+order by timestamp desc
+limit 50;
+```
### Disabling read-only mode
@@ -136,7 +153,7 @@ First, change the [transaction access mode](https://www.postgresql.org/docs/curr
set session characteristics as transaction read write;
```
-This allows you to delete data from within the session. After deleting data, consider running a vacuum to reclaim as much space as possible:
+This allows you to delete data from within the current session. After deleting data, consider running a vacuum to reclaim as much space as possible:
```sql
vacuum;
@@ -148,6 +165,12 @@ Once you have reclaimed space, you can run the following to disable [read-only](
set default_transaction_read_only = 'off';
```
+
+
+`SET SESSION CHARACTERISTICS` applies only to the current session. Background jobs and scheduled tasks resume writes automatically once the platform exits read-only mode — no manual step is needed.
+
+
+
### Disk size distribution
You can check the distribution of your disk size on your [project's Infrastructure page](/dashboard/project/_/settings/infrastructure).