MongoDB not primary and secondaryOk=false: reading from a secondary and how to fix it

Your application logs show NotPrimaryNoSecondaryOk (code 13435) with the message "not master and slaveOk=false". Metrics show read failures against a specific host. The mongod process is running, replica set heartbeats are clean, and replication lag looks normal. The cluster is not down. The error is a routing decision: a client sent a read to a replica set member that is not the primary, without declaring that reading from a non-primary is acceptable.

By default, only the primary serves reads. Secondaries replicate the oplog asynchronously and can serve reads only when the client explicitly requests a read preference that permits them. When a driver, shell, or application sends a read to a secondary without that permission, the secondary returns this error. The server is protecting data consistency. The problem is almost always on the client side.

This error spikes in three common situations: immediately after a primary failover, when stale driver topology still points to the old primary or a secondary; when an application is misconfigured with a read preference that routes to secondaries without handling fallback correctly; and when an operator runs ad-hoc queries against a secondary without enabling secondary reads.

What this means

A MongoDB replica set maintains a strict single-primary topology. Writes go to the primary. Secondaries tail the oplog in local.oplog.rs. Because secondaries may lag, clients must explicitly opt in to secondary reads via a read preference.

This error is classified as a retryable read error in the MongoDB driver specification. When retryable reads are enabled, the driver may automatically retry the operation against a different member that satisfies the read preference. If retryable reads are disabled, or if no member satisfies the current read preference, the error surfaces to the application as a hard failure. The secondary itself is almost always healthy. It is correctly refusing to serve a read it is not configured to serve. Treat this as a client routing problem, not a server outage.

Common causes

CauseWhat it looks likeFirst thing to check
Stale topology after failoverError spike begins exactly when a new primary is elected; may resolve after driver refreshrs.status() member states and election timestamps in logs
Driver read preference misconfigurationReads consistently fail against secondaries while working on the primaryConnection string for readPreference, directConnection, and driver options
Direct shell access to a secondary without secondaryOk()Ad-hoc queries fail on one node but succeed on anotherWhether the shell session targeted a secondary and if rs.secondaryOk() was run
Member in RECOVERING stateReads fail against a node that is catching up after restart or syncrs.status() stateStr for the target member
Single-node replica set with secondary preferenceApplication requires secondary reads but no secondary existsReplica set member count versus read preference mode

Quick checks

# Check current member states across the replica set
mongosh --quiet --eval 'rs.status().members.forEach(function(m){print(m.name + " -> " + m.stateStr)})'
# Check for recent elections that could invalidate cached topology
grep -iE "election|stepping down|not electable|vote" /var/log/mongodb/mongod.log | tail -20
// Check if any member is in RECOVERING or another non-readable state
rs.status().members.forEach(function(m) {
  if (m.stateStr !== 'PRIMARY' && m.stateStr !== 'SECONDARY') {
    print(m.name + ': ' + m.stateStr);
  }
})
// Check incoming connections and churn
var c = db.serverStatus().connections;
print('Current: ' + c.current + ' Available: ' + c.available + ' Total created: ' + c.totalCreated);

How to diagnose it

  1. Identify the target node. From the application error or connection logs, determine the host:port of the MongoDB node that returned the error. If the driver does not log the specific server, check the connection string for candidate hosts.
  2. Verify the node’s current role. Run rs.status() from a healthy member. Check stateStr for the target host. If it is SECONDARY, the client routed a read to a secondary without permission. If it is PRIMARY, the client is using stale topology or a direct connection.
  3. Check for recent elections. Search the MongoDB logs on the target node for "Starting an election" or "Stepping down". Failover events invalidate the old primary. Drivers should refresh topology within seconds, but some configurations or network partitions delay this. If the target node was previously primary, the client is definitely using stale topology.
  4. Inspect the application connection string. Look for readPreference=secondary, readPreference=secondaryPreferred, directConnection=true, or no read preference at all. If the string uses secondary, confirm the replica set has at least one healthy SECONDARY. If it uses primary or omits the option, confirm the driver is not overriding it elsewhere.
  5. Check for RECOVERING members. A node in RECOVERING cannot serve reads even with secondaryPreferred. Verify all expected secondaries show stateStr: "SECONDARY" and health: 1.
  6. Validate driver retry behavior. Modern drivers enable retryable reads by default. If the application uses an older driver or explicitly disables retries, transient NotPrimaryNoSecondaryOk errors during failover will not self-heal.

Metrics and signals to monitor

SignalWhy it mattersWarning sign
Replica set member stateIdentifies whether the target node is PRIMARY, SECONDARY, or RECOVERINGNode is SECONDARY or RECOVERING when reads fail
Election eventsElections change the primary and invalidate cached topologyLog entries for elections coincide with error spikes
Replication lagHigh lag can cause a secondary to enter RECOVERING or fall off the oplogLag >10 seconds sustained on secondaries
Connection utilizationReconnection storms after failover delay recovery and amplify errorstotalCreated delta spikes after topology changes
Assertion counts (user)Client-side errors increment user assertions; spikes may reveal misconfigurationSustained increase in user assertion rate

Fixes

Stale topology after failover

Do not restart mongod. The server is healthy. The driver’s cached view of the replica set topology is stale. Ensure the application uses a modern driver with retryable reads enabled. If errors persist after the cluster has elected a stable primary, restart the application process to force the driver to rebuild its connection pool and topology map. This is disruptive, so use it only after the cluster is stable.

Check the driver’s serverSelectionTimeoutMS and heartbeatFrequencyMS. A heartbeat frequency that is too low delays detection of stepdowns. A serverSelectionTimeoutMS that is too short may cause the driver to give up before finding the new primary. The default serverSelectionTimeoutMS is typically 30 seconds; do not lower it unless you understand the tradeoff.

Misconfigured read preference

If the application intends to read from secondaries, update the connection string to use a read preference that matches the topology reality. Use readPreference=secondaryPreferred instead of secondary unless the application explicitly requires failure when no secondary is available. primaryPreferred is safer for workloads that prefer the primary but can tolerate occasional secondary reads during failover. nearest routes to the member with the lowest latency based on local measurements.

Multi-document transactions must use the primary read preference. All operations in a transaction must route to the same member. Attempting to use secondary inside a transaction will fail.

For ad-hoc queries in mongosh against a secondary, run rs.secondaryOk() before querying. Do not use rs.slaveOk(), which is deprecated and may be removed.

Member in RECOVERING state

Wait for the member to finish initial sync or oplog catch-up. Check rs.status() for stateStr. If the member remains in RECOVERING for more than a few minutes, investigate storage latency, network throughput between members, or oplog window size. Reads against a recovering node will fail regardless of read preference. Do not attempt to force reads against it.

Single-node replica sets

A replica set with one member has no secondary. Any readPreference=secondary configuration will fail immediately because no eligible secondary exists. Change the application to use primary or primaryPreferred. If you need secondary reads for load distribution, add members to the replica set.

Prevention

  • Use secondaryPreferred rather than secondary unless your application explicitly requires failure when no secondary exists. secondaryPreferred falls back to the primary when secondaries are unavailable, which prevents outages during maintenance or failover.
  • Enable retryable reads in the driver to absorb transient routing errors during failover without application-level retries.
  • Monitor election events and alert on any unexpected election outside maintenance windows. A single unexpected election is a stability concern.
  • Use the replica set connection string format with multiple seed hosts so drivers can discover the current primary without relying on a single endpoint. Single-host connections are more fragile during failovers. Avoid directConnection=true in replica set applications unless you are intentionally connecting to a single node.
  • Keep MongoDB drivers current. Older drivers have slower topology refresh and weaker handling of stepdown events.
  • If your application cannot tolerate stale data, avoid routing reads to delayed secondaries. Use maxStalenessSeconds to exclude secondaries that are too far behind.

How Netdata helps

  • Replica set member state is collected continuously, so you see a node transition from PRIMARY to SECONDARY at the exact moment the error begins.
  • Election events can be surfaced through log monitoring or metric correlation, linking error spikes directly to failovers.
  • Replication lag per secondary shows whether secondaries are healthy enough to serve reads when secondaryPreferred is in use.
  • Connection utilization and totalCreated trends reveal reconnection storms that delay topology recovery.
  • Assertion counts (user, regular) help distinguish client misconfiguration from server-side degradation.