Oracle problems
ORA-01000: Maximum Open Cursors Exceeded. Which Session Leaks, Which Statement, and the Fix
3 November 2026
ORA-01000 reads like a database limit and is nearly always an application leak: one session, one statement, opened in a loop and never closed. The limit only decides on which day the leak is noticed. The session that hits it, the statement it holds open and the number to set are three queries away.
What the error says
ORA-01000: maximum open cursors exceeded. One session has more cursors open than OPEN_CURSORS allows. The limit is per session, not per database: a database with ten thousand cursors open across all sessions is fine, a session with 301 open when the limit is 300 gets the error. The default is 50, the range is 0 to 65535, and the parameter costs nothing until a cursor is actually opened.
Two things look like ORA-01000 and are not:
- ORA-00020, maximum number of processes: the database is out of processes for everyone, not one session out of cursors. That page.
- Pool exhaustion in the application: "could not get connection from the pool" comes from the middle tier, with no ORA code, and the database may be idle.
Which session is near the limit
The statistic that counts is opened cursors current in V$SESSTAT, compared with the parameter:
SELECT s.sid, s.serial#, s.username, s.program, s.machine,
st.value AS open_now,
ROUND(st.value / p.lim * 100, 1) AS pct_of_limit
FROM v$sesstat st
JOIN v$statname n ON n.statistic# = st.statistic#
AND n.name = 'opened cursors current'
JOIN v$session s ON s.sid = st.sid
CROSS JOIN (SELECT TO_NUMBER(value) AS lim
FROM v$parameter
WHERE name = 'open_cursors') p
WHERE s.type = 'USER'
ORDER BY st.value DESC
FETCH FIRST 15 ROWS ONLY;
A healthy application sits far below the limit in every session. A leak shows as one or a few sessions near the top, all from the same program, and the number grows while the others stay flat.
Which statement it holds open
V$OPEN_CURSOR lists every cursor a session has, with the statement. Group it for the session from the first query:
SELECT oc.sql_id, oc.cursor_type, COUNT(*) AS cursors,
MIN(SUBSTR(oc.sql_text, 1, 60)) AS sql_text
FROM v$open_cursor oc
WHERE oc.sid = :sid
GROUP BY oc.sql_id, oc.cursor_type
ORDER BY cursors DESC
FETCH FIRST 10 ROWS ONLY;
The leak is the row with one SQL_ID and hundreds of cursors of type OPEN: the application prepares the same statement again on every iteration and closes none of them. Rows of type SESSION CURSOR CACHED or PL/SQL CURSOR CACHED are Oracle's own caching and not the leak. Without a session number, the same grouping over the whole database names the statement to look for in the code:
SELECT oc.sql_id, COUNT(*) AS cursors,
COUNT(DISTINCT oc.sid) AS sessions,
MIN(SUBSTR(oc.sql_text, 1, 60)) AS sql_text
FROM v$open_cursor oc
WHERE oc.cursor_type LIKE 'OPEN%'
GROUP BY oc.sql_id
ORDER BY cursors DESC
FETCH FIRST 10 ROWS ONLY;
The fix, in order
- Give the application room now. The parameter is dynamic:
ALTER SYSTEM SET open_cursors = 1000 SCOPE = BOTH;(addSID = '*'on RAC). A cursor uses memory only when it is open, so a higher ceiling costs nothing for sessions that never reach it. This stops the paging; it does not stop the leak, which reaches 1000 a few hours later. - Close the leak in the code. The SQL_ID from the second query points at the statement. In Java every
PreparedStatementandResultSetis closed in a finally block or a try-with-resources; in .NET the command and the reader are disposed; in PL/SQL every explicit cursor is closed and everyDBMS_SQLcursor getsCLOSE_CURSOR. A driver's statement cache is not a leak: it is bounded by its own size. - Free the session if the application cannot. A session that holds 300 cursors and does nothing keeps them until it disconnects.
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;returns them; the pool opens a clean connection. - Set the number from the data, not from a forum. Rerun the first query at the busiest hour once the leak is closed. The highest session plus half again is the limit; 1000 covers most applications, batch programs with many open result sets need more.
See it coming
A leak is invisible at any single reading: 180 cursors in a session today, 200 tomorrow, each normal on its own. Radar Engine, the detection layer of Scops, reads the shape, and it reads it without an agent on the server:
| Detector | Clock | When it fires |
|---|---|---|
| Open cursors leak | Hourly, against the session count | Open cursors rise for days while sessions do not: Watch. Doubled: Warning. |
| Sessions near the limit | Hourly level and forecast, against sessions | 70%: Watch. 80%: Warning. 90%: Critical. |
| Session surge | Live, against the hour before | A pool that reconnects after ORA-01000 shows here first. |
The finding names the database and the day the leak started, so the deploy that introduced it is one calendar look away, and the session breakdown shows which program carries it.
Questions
Does a higher OPEN_CURSORS cost memory?
No. A cursor takes memory when it is opened, the parameter is only the ceiling. Oracle's own reference says there is no added overhead in setting it higher than a session uses.
Is ORA-01000 a database problem or an application problem?
Almost always the application: one statement, prepared in a loop and never closed. The database limit decides only when the leak is noticed. Raise it to buy time, then fix the code.
Does SESSION_CACHED_CURSORS fix it?
No. It caches the cursors of repeated statements so that they parse faster; it does not close what the application left open.
Why is ORA-01000 not in the alert log?
It is returned to the session that caused it, like any statement error, so it appears in the application's log. The database-side trace is the first query, run before the session disconnects.
Related problems
- ORA-00020: maximum number of processes
- ORA-04031: shared pool out of memory
- Blocking sessions: find the root blocker
- All Oracle problems
Sources
- Oracle: ORA-01000, OPEN_CURSORS, SESSION_CACHED_CURSORS, V$OPEN_CURSOR
- Scops docs: Detector reference