- Error code
- ORA-01000
- Product
- Oracle Database
- Versions
- Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
- Category
- Space, Memory & Resource Limits
- Last reviewed
- 24 October 2026
On this page
What it means
ORA-01000 means one database session tried to have more cursors open at the same time than the OPEN_CURSORS initialization parameter allows, usually because the application opens statements or result sets and does not close them.
Every SQL statement a session runs uses a cursor, and OPEN_CURSORS (default 50 in the 19c Database Reference) caps how many a single session may hold open at once. Oracle's current reference names two root causes: the workload genuinely needs more concurrently open cursors than the limit, or the application has a cursor leak, opening cursors and never closing them, or closing them later than needed. A leak makes the count climb steadily until the session fails, often hours after a connection pool handed it out.
In current releases the message template ends with an extra detail field, and Oracle's Action text says the error text may identify a potentially leaked SQL_ID for a developer to review; the exact content of that field is not documented, so this page shows the message without it. 19c and 21c print "maximum open cursors exceeded". Raising the limit stops the error only when the workload really needs more cursors; with a leak it just delays it.
Common causes
- Application code (JDBC, ODP.NET, Python and so on) creates statements or result sets in a loop and does not close them, especially on error paths.
- A PL/SQL function returns a SYS_REFCURSOR to the client, and the client never closes the result set.
- Dynamic SQL with DBMS_SQL.OPEN_CURSOR runs without a matching DBMS_SQL.CLOSE_CURSOR.
- A client-side statement cache is set larger than OPEN_CURSORS allows, so cached statements alone fill the session's quota.
- The workload legitimately needs many open cursors per session (complex batch jobs, many prepared statements) and OPEN_CURSORS is too low for it.
Diagnose it
Read-only These queries only read the data dictionary (USER_, ALL_ and DBA_ views) and dynamic performance views (V$). They do not change data, privileges or settings, so they are safe to run first. DBA_ and V$ views need the matching privileges.
Check the limit
SELECT name, value
FROM v$parameter
WHERE name IN ('open_cursors', 'session_cached_cursors'); The per-session limit. Querying V$ views needs a privilege such as SELECT_CATALOG_ROLE or SELECT ANY DICTIONARY, so run these checks from an administrative connection, as Oracle's reference suggests.
Which sessions are at or near the limit?
Based on the query in Oracle's reference: the statistic "opened cursors current" is each session's number of open cursors right now.
SELECT s.sid, s.serial#, s.username, s.program, ss.value AS open_cursors
FROM v$sesstat ss
JOIN v$statname sn ON sn.statistic# = ss.statistic#
JOIN v$session s ON s.sid = ss.sid
WHERE sn.name = 'opened cursors current'
AND s.username IS NOT NULL
ORDER BY ss.value DESC
FETCH FIRST 20 ROWS ONLY; Sessions with a count equal to open_cursors are the ones failing. One program with steadily rising counts points to a leak in that program.
Which statements are holding the cursors?
V$OPEN_CURSOR lists cursors each session has open or cached, and its CURSOR_TYPE column separates open cursors from cached ones. The same SQL text repeated many times in one session is the classic sign of a leak.
SELECT sid, user_name, cursor_type, sql_id, sql_text, COUNT(*) AS copies
FROM v$open_cursor
WHERE user_name = 'SHOP_APP'
GROUP BY sid, user_name, cursor_type, sql_id, sql_text
ORDER BY copies DESC
FETCH FIRST 20 ROWS ONLY; A statement with a high copies count and cursor_type OPEN is a strong candidate for the leak; give its sql_id and text to the developer. Rows marked as cached are held by the session cursor cache and are not a leak by themselves.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Close every statement and result set in the application
Client or network sideOracle's Action text starts here: close cursors before opening new ones. Use the language's automatic cleanup so cursors close on errors too: try-with-resources for JDBC Statement and ResultSet, using blocks in .NET, context managers in Python. Close every ref cursor a procedure returns once you have read it.
Close cursors in PL/SQL, including on error paths
Changes schemaEvery DBMS_SQL.OPEN_CURSOR needs a CLOSE_CURSOR, and the exception handler must close it too. Cursor FOR loops open and close their cursor automatically and are the simplest choice for static SQL.
CREATE OR REPLACE PROCEDURE shop.run_dynamic (p_sql IN VARCHAR2) IS
c INTEGER := DBMS_SQL.OPEN_CURSOR;
rows INTEGER;
BEGIN
DBMS_SQL.PARSE(c, p_sql, DBMS_SQL.NATIVE);
rows := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(c) THEN
DBMS_SQL.CLOSE_CURSOR(c);
END IF;
RAISE;
END;
/
Raise OPEN_CURSORS only when the workload needs it
Changes configurationIf monitoring shows that sessions need more cursors in normal operation and are not leaking, raise the limit. The 19c Database Reference lists OPEN_CURSORS as modifiable with ALTER SYSTEM and says that a higher setting adds no overhead as long as sessions do not actually open that many cursors.
Caution: Needs the ALTER SYSTEM privilege and affects every session of the instance (or PDB). SCOPE = BOTH requires a server parameter file. With a leak, a higher limit only postpones the error and lets each leaking session hold more memory, so fix the code first.
ALTER SYSTEM SET open_cursors = 1000 SCOPE = BOTH;
Examples
Dynamic SQL that never closes its cursor
Not reproduced here: no Oracle Database is installed for this site. The first line follows Oracle's current error reference without the trailing detail field, whose content is not documented; the ORA-06512 line and its line number are illustrative, and the full stack may include lines from SYS.DBMS_SQL. Oracle Database 19c and 21c print "ORA-01000: maximum open cursors exceeded".
-- open_cursors = 300
DECLARE
c INTEGER;
BEGIN
FOR i IN 1 .. 1000 LOOP
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, 'SELECT 1 FROM dual', DBMS_SQL.NATIVE);
-- missing: DBMS_SQL.CLOSE_CURSOR(c);
END LOOP;
END;
/
ORA-01000: maximum open cursors for session exceeded ORA-06512: at line 6
Ref cursors returned to an application that never closes them
Not reproduced here: no Oracle Database is installed for this site. The message format comes from Oracle's error reference (shown without the current releases' trailing detail field). The error appears on whichever call reaches the limit, often far from the code that leaks; V$OPEN_CURSOR shows the SELECT from orders many times for that session.
CREATE OR REPLACE FUNCTION get_customer_orders (p_customer_id IN NUMBER)
RETURN SYS_REFCURSOR
IS
rc SYS_REFCURSOR;
BEGIN
OPEN rc FOR SELECT order_id, amount FROM orders WHERE customer_id = p_customer_id;
RETURN rc;
END;
/
-- the application calls this once per customer on one pooled connection
-- and reads each result set, but never closes it
ORA-01000: maximum open cursors for session exceeded
How to prevent it
Make closing automatic: try-with-resources, using blocks or context managers for every statement and result set, cursor FOR loops in PL/SQL, and an exception handler that closes any DBMS_SQL cursor. Review code paths that return early or throw.
Monitor the "opened cursors current" statistic per session (Oracle's reference gives a query for it) to learn how many cursors normal operation needs, and size OPEN_CURSORS and client statement caches from that, with headroom. A count that only ever rises is a leak.
Common questions
How do I fix ORA-01000 maximum open cursors exceeded?
Find the session and statement holding the cursors with V$SESSTAT ("opened cursors current") and V$OPEN_CURSOR, then close statements, result sets and ref cursors in the application. Raise OPEN_CURSORS only if the workload genuinely needs more open cursors at once.
Is it safe to just set OPEN_CURSORS very high?
Oracle's Database Reference says a higher value adds no overhead while sessions do not open that many cursors, but with a leak the count keeps rising and the error returns later, with more memory used per session. Fix leaks first and size the limit from measured usage.
Why does V$OPEN_CURSOR show more cursors than the limit?
V$OPEN_CURSOR lists cursors that are open and also those that are only cached (see its CURSOR_TYPE column). The "opened cursors current" statistic in V$SESSTAT is the number to compare with OPEN_CURSORS.
Official documentation
- ORA-01000 (Oracle Database Error Messages)
- OPEN_CURSORS (Oracle Database Reference 19c)
- V$OPEN_CURSOR (Oracle Database Reference 19c)
- SESSION_CACHED_CURSORS (Oracle Database Reference 19c)
Last technically reviewed 24 October 2026; examples and diagnostics run on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally. Messages and explanations follow Oracle's Database Error Messages reference; no Oracle Database was available, so the examples were not run locally.