📍 Dhanmondi, Dhaka-1205🇧🇩 বাংলা

ORDS Connection Pool Failures: Why APEX Breaks After a Restart (and the Reboot-Safe Fix)

When APEX or ORDS fails straight after a restart or an upgrade, the database is rarely the problem. Usually ORDS either cannot find its configuration folder, or an ORDS connection pool's stored password no longer matches the database. Check those two things, in that order, and most of these outages end in minutes.

I learned that order on a pharmaceutical company's Oracle stack in May 2026. Every APEX link returned 404, The request could not be mapped to any database, although all eight pools were sitting on disk, unbroken.

Tomcat had started ORDS without telling it where its configuration lived. One line in setenv.sh brought seven pools back; the eighth had a stale wallet password, and fixing it quietly broke a neighbour.

Key Takeaways

  • An ORDS 404 saying the request could not be mapped to any database after a restart usually means ORDS loaded no pools, even when ords config list looks healthy.
  • Standalone ORDS reads --config, ORDS_CONFIG or the current directory. Under Tomcat or WebLogic it needs the config.url system property, or a WAR built with the location inside.
  • Since ORDS 24.2, pool failures have their own codes: 570 locked account, 571 network, 572 overloaded, 574 bad or expired credentials. Older releases send a 503.
  • Pools that log in to one database as ORDS_PUBLIC_USER share one password. Change it and every one of those pools needs ords config secret db.password.
  • Pool defaults change between releases (jdbc.InitialLimit is 10 in the 23.4 guide and 0 in 26.3), so size pools from measured peak sessions.
  • A fix is reboot-safe only when it lives in a file the service manager reads and survives a real, hands-off reboot.
Rows of industrial pipes and valves feeding a single line, a picture of an ORDS connection pool sharing reusable connections to one Oracle database
A pool keeps lines open to one source. Lose the map and none of them carries anything. Photo: Pavel Danilyuk / Pexels

1. What Is an ORDS Connection Pool?

An ORDS connection pool is a set of database connections that Oracle REST Data Services opens and reuses for one database, defined by a folder under databases/ in the ORDS configuration directory. Each pool logs in as a runtime user, normally ORDS_PUBLIC_USER, and the folder name becomes the URL prefix that routes requests to it.

So a pool folder named sales serves /ords/sales/..., and the reserved default folder catches any request that no other pool claims.

/etc/ords/config/               # the configuration folder
+- global/
|  +- settings.xml              # instance-wide settings
+- databases/
   +- default/                  # catches requests no other pool claims
   |  +- pool.xml
   |  +- wallet/cwallet.sso     # this pool's credentials
   +- sales/                    # serves /ords/sales/...
      +- pool.xml
      +- wallet/cwallet.sso

The password is not in pool.xml. Oracle's configuration file reference says the credentials must be stored in the pool's auto-login wallet, and that the db.password setting must not be used.

So when a pool reports a credential error, the broken thing is usually a small file called cwallet.sso, not the database.

2. Which ORDS Error Points to Which Layer?

Read the status code and the message together, and ORDS tells you which layer failed.

What you seeWhat it usually meansCheck first
404 could not be mapped to any databaseNo pool matched; after a restart, often none were loadedThe configuration inputs of the live process (section 8, step 1)
503, pool "not correctly configured" (before 24.2)A generic pool failureThe log line naming the pool and the ORA- code
570 Account Is LockedThe pool's account is lockedDBA_USERS
571 Database Connection ErrorNetwork or listener, such as ORA-12514 or ORA-12506Listener, service name, firewall
572 Recoverable Database Connection ErrorNo connection available, for example an overloaded databaseSessions, processes, jdbc.MaxLimit
574 Database Credential ErrorInvalid or expired passwordThe pool wallet against the database
...not authorized to proxy to the schema...A missing proxy grantDBA_PROXIES

The ORDS 24.2 release notes added the 57x codes to help log monitoring and alarms. On older releases those rows all arrive as 503, and only the log shows the difference.

A 571 is a listener problem wearing an ORDS badge, and my guide to listener and TNS troubleshooting for ORA-12514 covers it. A 413 on an APEX import is your proxy, not a pool, as I explained in fixing 413 Request Entity Too Large behind nginx.

3. How Does ORDS Find Its Configuration Folder?

Most post-restart failures start here. The running service decides where to look, not the command-line tool you configured it with.

Standalone mode (ords serve)

The install guide names three sources: the --config option, the ORDS_CONFIG environment variable, and, if neither is set, the current working directory. That fallback is the trap, because a service manager rarely starts ORDS from the folder you tested in.

Tomcat and WebLogic (ords.war)

A Java container has no --config flag. Oracle's deployment guide says the location must come from the config.url system property, or from a WAR generated with the ords war command, which it calls the recommended approach.

This is why ords config list can show eight healthy pools while the running container has loaded none. The tool reads the folder you name with --config; the container reads only what it was started with.

DeploymentHow the location is givenReboot-safe place for it
Standalone, your own unitords --config /etc/ords/config serveThe unit's ExecStart line
Standalone, from the RPMThe packaged serviceThe ords.conf file the install guide names
Apache Tomcat 9-Dconfig.url=/etc/ords/configbin/setenv.sh; on a Windows service, its Java options
WebLogic 14.1.2-Dconfig.url in JAVA_OPTIONS, or a WAR from ords warsetUserOverrides.sh, or the server's start arguments

Both containers also name the context root after the WAR file, so renaming ords.war changes the URL. Oracle's current checklist supports Tomcat 9.0.x and WebLogic 14.1.2, on Java 17 or 21.

A person in a white coat reaching into an open drawer of labelled cards in a white cabinet, like the ORDS configuration folder that Tomcat must be told about with config.url
The configuration was in the drawer all along. Nobody told ORDS which drawer. Photo: Tima Miroshnichenko / Pexels

4. What Went Wrong on the Pharmaceutical Stack?

The stack was ordinary: Apache terminating TLS, ords.war on Tomcat 9, and a group of Oracle databases behind them. The configuration held a default pool plus seven named pools spread across the group's databases.

Every /ords/ URL returned 404, yet the proxy was correct and every pool folder was present. Tomcat's command line simply carried no -Dconfig.url, so ORDS had started with nothing to map requests to.

Fix one: tell Tomcat where the configuration lives

# $CATALINA_BASE/bin/setenv.sh  (owned by the OS user that runs Tomcat)
export CATALINA_OPTS="$CATALINA_OPTS -Dconfig.url=/etc/ords/config"

Tomcat's documentation recommends a setenv script for this and keeps start-only options in CATALINA_OPTS; Oracle's guide uses JAVA_OPTS, and either works for a system property.

Two details cost time. Tomcat had to start as the OS user that owns its files, not as root, and a shutdown that never released port 8005 made the next start fail until the old process was cleared.

Seven pools answered at once.

Fix two: the pool with the stale wallet

The default pool failed with ORA-01017. Its wallet was more than a year old, and the password inside it no longer matched ORDS_PUBLIC_USER on that database.

I reconfigured that pool cleanly, which regenerated its wallet and set a new ORDS_PUBLIC_USER password in the database. Then a named pool on the same database, still holding the old password, started returning 574.

# set the secret at a prompt - never as a command-line argument
ords --config /etc/ords/config config --db-pool <pool> secret db.password
# then restart the container and re-test every pool

All eight answered after that. The lesson I kept: a password belongs to a database user, not to a pool, so rotating it means updating every pool that logs in as that user.

Fix three: one WAR, not four

The product folder also held three renamed copies of ords.war, and the ords command printed a stray Unknown command line on every run. One WAR serves every pool, and moving the copies out silenced the noise.

The box was also rebooted on purpose. Every service came back untouched, and Tomcat came up with -Dconfig.url on its command line.

5. Why Do ORDS Pools Break After an Upgrade or Reinstall?

Upgrades break pools in a few predictable ways, and every one of them looks like a database fault.

  • A password changed. A reinstall or reconfiguration can reset ORDS_PUBLIC_USER, while the other pools on that database keep the old password.
  • The configuration moved. ORDS 22.1 introduced today's command-line tool, the old apex.xml pool corresponds to the default folder, and the installer's --legacy-config option migrates an old layout.
  • APEX went in after ORDS. The install guide's default gateway mode is disabled. In that case Oracle says to set plsql.gateway.mode to proxied, or the gateway APEX needs stays off.
  • Java changed. ORDS needs Java 17 or 21 and refuses older versions with ORDS requires Java 17 and above to run. On the pharmaceutical stack, sudo -u oracle dropped JAVA_HOME, and sudo -i -u oracle fixed it.
  • A password expired. A PASSWORD_LIFE_TIME in the user's profile fails the pool on a schedule nobody wrote down, which shows as 574 on 24.2 and later.

On WebLogic, remember that ORDS builds its own Universal Connection Pools from its configuration folder, so tuning a JDBC data source changes nothing. My WebLogic administration guide covers the data sources WebLogic does own.

6. What Do ORDS_PUBLIC_USER and APEX_PUBLIC_USER Actually Do?

ORDS connects as one low-privilege user, then proxies to whoever should run the request.

AccountWhat it doesWhat fails when it breaks
ORDS_PUBLIC_USERThe runtime user in db.username; proxies to ORDS-enabled schemas or the gateway userEverything on that pool
ORDS_METADATAHolds ORDS metadata; ORDS never connects to itNothing directly; it is not a pool user
APEX_PUBLIC_USERThe minimally privileged APEX account, reached by proxyAPEX pages
APEX_REST_PUBLIC_USERUsed to invoke RESTful Services defined in APEXREST services defined in APEX
-- run as a DBA on every database a pool points at
SELECT username, account_status, expiry_date, profile
FROM   dba_users
WHERE  username IN ('ORDS_PUBLIC_USER','APEX_PUBLIC_USER','APEX_REST_PUBLIC_USER');

-- which users may ORDS_PUBLIC_USER proxy to?
SELECT proxy, client FROM dba_proxies WHERE proxy = 'ORDS_PUBLIC_USER';

On the pharmaceutical stack the chain was exactly that, and APEX routed workspaces to schemas itself. So do not grant proxy rights to every application schema to "fix" an app; that widens what a stolen pool credential can reach.

7. How Should You Size jdbc.InitialLimit, MinLimit and MaxLimit?

Pool settings are per pool and are changed with ords config --db-pool <pool> set. Oracle's configuration reference documents these defaults:

SettingWhat it controlsDocumented default
jdbc.InitialLimitConnections opened when the pool starts10 in the 23.4 and 24.4 guides; 0 in 25.4 and 26.3
jdbc.MinLimitThe minimum number of connections2
jdbc.MaxLimitThe ceiling on connections10, which "might be too low for some production environments"
jdbc.InactivityTimeoutIdle seconds before a connection is closed1800

The first row changed between releases, which is why I never copy pool numbers from a blog post, this one included. Measure instead, several times through your busiest hour:

SELECT username, status, COUNT(*) AS sessions
FROM   v$session
WHERE  username IN ('ORDS_PUBLIC_USER','APEX_PUBLIC_USER','APEX_REST_PUBLIC_USER')
GROUP  BY username, status
ORDER  BY username, status;

Proxied work can appear under the target user, hence all three names. Keep the highest ACTIVE figure, add headroom, and set jdbc.MaxLimit there.

Then multiply that ceiling by the pools on that database and by your ORDS instances, and compare it with the database's processes and sessions parameters: eight pools at 30 each can ask one ORDS node for 240 connections.

# example value only - derive yours from the query above
ords --config /etc/ords/config config --db-pool <pool> set jdbc.MaxLimit 30
ords --config /etc/ords/config config --db-pool <pool> list --include-defaults

Keep jdbc.InactivityTimeout below any firewall idle timeout between the tiers, or the pool may hold connections the firewall has already dropped.

jdbc.MaxConnectionReuseCount, documented with a default of 1000, retires a connection after that many uses and replaces it with a fresh one. Leave it alone unless you have a measured reason to change it.

A person typing at a keyboard in front of a monitor in a server room, with network racks and cables behind
Read the log before you restart anything. The restart deletes the evidence. Photo: panumas nikhomkhai / Pexels

8. How Do You Diagnose a Failing ORDS Pool, Step by Step?

This is the order I follow now. Each step rules out one layer, and the first three take seconds.

  1. Check what the running ORDS was actually given, looking only at the inputs your deployment reads (section 3; the commands are in the box after this list). Standalone (ords serve): --config on its command line, then ORDS_CONFIG in its environment, then the working directory it started in. Tomcat or WebLogic (ords.war): -Dconfig.url on the JVM command line, or a config.url that ords war set inside the deployed WAR.
  2. List the pools on disk. Run ls /etc/ords/config/databases/ (on Windows, dir in your configuration folder): one folder, one pool, one URL prefix.
  3. Read each pool's settings. Run ords --config /etc/ords/config config --db-pool <pool> list. In its Source column, db.password should say Pool Wallet.
  4. Read the log before restarting. Use catalina.out, the WebLogic server log, or the ords serve console, and look for the pool name and an ORA- code.
  5. Test every pool with the loop below, not only the broken one.
  6. Check the accounts on each database with the queries in section 6.
  7. Set the secret at a prompt with ords config --db-pool <pool> secret db.password. Oracle warns that a value passed as an argument shows in ps output.
  8. Restart cleanly, with the old process gone and its ports free, then re-test everything.

Step 1 in detail, on Linux

These commands read /proc and use systemd, so they work on Linux only. Run them as root or as the user that runs ORDS: the kernel checks permission before anyone reads another process's environment or working directory.

# Linux only (systemd + /proc). 1. the PID of the running ORDS JVM
PID=$(systemctl show -p MainPID --value ords.service)   # or your Tomcat unit's name
pgrep -af 'org.apache.catalina.startup.Bootstrap|ords\.war|ords serve'   # no unit? list the candidates

# 2. both deployments: the command line the JVM started with
tr '\0' ' ' < /proc/$PID/cmdline; echo
#    standalone: look for --config     Tomcat / WebLogic: look for -Dconfig.url=

# 3. standalone only: ORDS_CONFIG, then the folder it started in
tr '\0' '\n' < /proc/$PID/environ | grep '^ORDS_CONFIG='
( cd /proc/$PID/cwd && pwd -P )

# 4. Tomcat / WebLogic only: a config.url that `ords war` put inside the WAR
#    (use the WAR file you actually deployed)
unzip -p /path/to/tomcat/webapps/ords.war 'WEB-INF/*.xml' | grep -i -A2 'config.url'

On Windows there is no /proc and no systemctl. Find the ORDS process with jps -ml, the command Oracle's deploying and monitoring guide gives, and read the Java options the Tomcat service or WebLogic server was started with (section 3).

Call it a missing configuration only when every input your deployment reads is empty, or names a folder with no pools under databases/. That is what users then see: on the pharmaceutical stack, every /ords/ URL answered 404 with The request could not be mapped to any database.

# step 5 (bash): every named pool, through the same path your users take
for p in sales finance hr; do          # your pool folder names
  printf '%-10s %s\n' "$p" "$(curl -k -s -o /dev/null -w '%{http_code}' https://localhost:8443/ords/$p/)"
done

On the pharmaceutical stack, healthy named pools answered 302, a redirect into the application. The default pool needs a real application URL instead, as the FAQ explains.

On a live system, the Instance API at /ords/_/instance-api/stable/status counts valid and invalid pools once instance.api.enabled is set (it needs the System Administrator role). ords pool --pid <pid> list shows a running instance's pools without a restart; both are in Oracle's deploying and monitoring guide.

9. How Do You Make the Fix Survive a Reboot?

A fix typed into a shell is not a fix yet. It must live where the service manager reads it, and a real reboot must prove it.

  • Use the file the service reads. That is setenv.sh for Tomcat, setUserOverrides.sh or the start arguments for WebLogic, and ExecStart or ords.conf for standalone. An export typed into your session dies at logout.
  • Run as the owner. One start as root can leave root-owned files behind that break the next normal start.
  • Let systemd see the JVM. There, a Type=forking Tomcat unit whose stop script failed left the old JVM holding its ports, and the automatic restart looped on Address already in use. Running catalina.sh run in the foreground under Type=simple is the cleaner design.
  • Protect and archive the folder. It holds every pool's wallet, so restrict it to the ORDS owner. Take a dated archive of it, and of setenv.sh, before each change.
# Linux only (systemd, /proc, ss): after a deliberate reboot - no manual starts allowed
systemctl --failed
PID=$(systemctl show -p MainPID --value ords.service)   # or your Tomcat unit's name
tr '\0' ' ' < /proc/$PID/cmdline | grep -oE -- '-Dconfig.url=[^ ]+|--config +[^ ]+'
tr '\0' '\n' < /proc/$PID/environ | grep '^ORDS_CONFIG='   # standalone only
ss -tlnp | grep -E ':8443|:8080'       # your container's ports
# then the per-pool loop from section 8, plus one real app URL for default

On Windows, the same proof is the service list after the reboot, jps -ml for the ORDS process and the same per-pool URLs. The test passes only if nobody touches the box between power-on and the last pool check. That test is what proved the setenv.sh fix permanent.

A close-up of the power key at the corner of a silver laptop's keyboard - the reboot that proves an ORDS configuration fix survives a restart
Press it on purpose, on a quiet afternoon, before an outage presses it for you. Photo: energepic.com / Pexels

10. What Else Looks Like a Pool Failure but Is Not?

Redirects to plain http behind TLS. If the proxy sends no X-Forwarded-Proto: https and Tomcat does not trust it (a RemoteIpValve does that), ORDS redirects users to http, which an outside firewall may simply block.

On the pharmaceutical stack this looked like ORDS working inside the office and hanging from outside. LAN browsers quietly followed the http redirect, while the outside firewall dropped port 80.

Two configuration folders. An old run of ords without --config can leave a second configuration in the product folder, which Oracle advises against. Keep exactly one.

For anything else, my systematic method for diagnosing Oracle errors applies unchanged.

Most ORDS connection pool outages after a restart come down to two questions. Did the running process get its configuration folder, and does every pool's wallet still match the database today?

Frequently Asked Questions

Why does ORDS say the request could not be mapped to any database?

No pool matched the URL, and after a restart that usually means ORDS loaded no pools at all. Under Tomcat or WebLogic, check the running JVM for -Dconfig.url and the deployed WAR for a config.url set by ords war; in standalone mode, check --config, ORDS_CONFIG and the folder ORDS was started in. If the configuration did load, check that the URL prefix matches a folder under databases/.

Where does ORDS look for its configuration folder?

Standalone ORDS uses the --config option, the ORDS_CONFIG variable or, failing both, the current working directory. In Tomcat or WebLogic the location must come from the config.url system property or from a WAR built with ords war. Oracle recommends keeping the folder outside the ORDS product folder.

What does ORDS error 574 mean?

Since ORDS 24.2, status 574 is a database credential error, such as an invalid or expired password for the pool's user. ORDS reads that password from the pool's wallet, so reset it with ords config --db-pool <pool> secret db.password if it no longer matches. Older releases report the same failure as a 503.

How do I change the ORDS_PUBLIC_USER password without breaking pools?

First list every pool that logs in as ORDS_PUBLIC_USER on that database, because they all share one password. Change it in the database, run ords config --db-pool <pool> secret db.password for each of those pools, and restart ORDS. Then test every pool, not only the one you meant to fix.

What is a good value for jdbc.MaxLimit?

There is no universal number. The documented default is 10, which Oracle says might be too low for some production environments. Measure peak active sessions for the pool users, add headroom, and confirm the total across pools and ORDS instances fits the database's processes and sessions limits.

Is ORDS standalone mode supported in production?

Yes. Oracle's deployment guide says standalone mode is suitable for development and supported in production, though it has fewer management features than a Java EE application server. Oracle also recommends running it with HTTPS rather than HTTP.

Why does /ords/default/ return 404 when the default pool works?

The default folder is reserved for requests that no other pool claims, so it is not meant to be addressed by name. On the stack in this article, /ords/default/ returned 404 while real application URLs on that pool worked normally. Test the default pool with a real application URL instead.

🔒 Is your ORDS tier exposing more than APEX?

Every pool wallet sits in one folder, and a container's plain-HTTP port is easy to leave reachable. If you would rather know what your middleware exposes before someone else checks, I will look at it properly.

🔍 Digital Exposure Audit
Nasir Uddin Khan — Oracle DBA Consultant

Nasir Uddin Khan

Nasir is an Oracle Certified Professional and CSV-certified IT consultant based in Dhaka, Bangladesh. He has 18+ years of hands-on experience in Oracle database administration (RAC, Data Guard, RMAN), WebLogic middleware, ERP system design, and AI integration for manufacturing, pharmaceutical, banking, and healthcare organisations worldwide.

References & Further Reading

The case was diagnosed and fixed by the author on a production system in May 2026; names are withheld and paths generalised. Confirm settings against the documentation for your ORDS release before production use.

Related Articles

APEX and ORDS That Survive the Next Reboot

ORDS and APEX deployment · Tomcat and WebLogic · connection pool tuning · exposure audits. 18+ years of Oracle experience. Bangladesh and worldwide.

💬