How to Control Read Restart Errors in YugabyteDB

Distributed SQL databases like YugabyteDB guarantee correctness across nodes, even when clocks drift, and sometimes that means YSQL will stop a query and ask you to retry it. These read restart errors protect you from accidentally reading stale data.

Starting in YugabyteDB 2024.1.1.0, the YSQL layer introduced new, more flexible ways to tune how strictly this guarantee is enforced.Β 

This Tip explains:

  • ● Why read restart errors happen

  • ● How YugabyteDB guarantees read-after-commit visibility

  • ● The different visibility modes (strict, relaxed, and deferred)

  • ● When to use each mode and when not to

  • ● Real-world examples (production vs. DBA/maintenance scenarios)

πŸ” Understanding Read Restart Errors

YugabyteDB promises:

  • Any read must see all data committed before the read began, even when nodes have clock skew.

To maintain this guarantee, YSQL compares:

  • ● The commit time of each row

  • ● The read time chosen for the transaction

If clock skew makes those timestamps ambiguous, YugabyteDB cannot safely confirm the row should be visible…. it refuses to guess and instead returns:

				
					ERROR:  Query error: Restart read required
SQLSTATE: 40001
				
			

This is intentional: returning a stale result would violate correctness.

βš™οΈ Where the Tuning Happens (Cluster Flags vs. Session GUC)

You can choose how strictly YSQL should enforce the read-after-commit visibility guarantee. The setting exists at two levels:

  • ● Cluster-level setting (masters + tservers)
    • β–£ Flag: ysql_yb_read_after_commit_visibility
      • β—¦ Default: strict (PG-like safety-first semantics)

      • β—¦ Must match on all masters and tservers

      • β—¦ Controls the default behavior for every YSQL session

  • ● Session-level GUC (yb_read_after_commit_visibility)
    • β–£ Inside any YSQL client:
				
					SHOW yb_read_after_commit_visibility;
SET yb_read_after_commit_visibility = 'relaxed';
				
			
        • β—¦ Reasons to use the session-level override:
            • β–ͺ Avoid read restarts for a specific workload
            • β–ͺ Avoid changing cluster-wide behavior
            • β–ͺ Enable special modes only for DBAs, scripts, or maintenance tools

This Tip focuses mostly on the session-level GUC, which gives you fine-grained control without touching cluster flags.

πŸ“˜ The Modes: strict, relaxed, and deferred
  • ● strict : the Default (and safest)
    • β—‹ This mode enforces full read-after-commit visibility.

        • β–ͺ Ensures no stale reads

        • β–ͺ Raises read restart errors when timestamp order is ambiguous

        • β–ͺ Matches PostgreSQL expectations

        • β–ͺ Used in all OLTP/production systems by default

    • βœ”οΈ When to Use strict
        • β–ͺ User-facing applications
        • β–ͺ Banking, financial, and ordering systems
        • β–ͺ Microservices that assume β€œcommit β†’ then message β†’ then read must show it”
        • β–ͺ Security and audit workloads
        • β–ͺ Anything requiring strong external consistency
    • ❌ When NOT to change away from strict
        • β–ͺ Never change this cluster-wide just to β€œsilence” read restarts
        • β–ͺ Never use a weaker mode for unpredictable, customer-visible queries
  • ● relaxed β€” reduce read restarts, accept possible staleness
    • β—‹ Introduced in YugabyteDB 2024.1.1.0-b137
    • β—‹ This mode tells YSQL: “If you can’t guarantee perfect visibility, return a result anyway.”
    • β—‹ In this mode you may miss very recent commits, but you greatly reduce the chance of read restart errors.
    • β—‹ Relaxed mode is only for read only statements/ transactions.
      • β–ͺ For read-only statements, the user doesn’t have to tag it as read-only, the db auto detects it read-onlyness.
      • Example:
				
					SET yb_read_after_commit_visibility = 'relaxed';

SELECT * FROM large_table WHERE category = 'X';
				
			
    • βœ”οΈ When relaxed is a good idea
      • β–ͺ yb_index_check() – The docs explicitly recommend using relaxed here
				
					SET yb_read_after_commit_visibility = 'relaxed';

SELECT *
FROM yb_index_check(
  'public.my_table',
  'public.my_table_idx',
  p_options := 'phase=all'
);
				
			
        • β—‡ Index checks do not depend on β€œlatest commit” visibility
        • β—‡ You just need a self-consistent snapshot
        • β—‡ Avoiding restarts dramatically speeds up checks on large datasets
      • β–ͺ Large analytical reads
        • β—‡ For example:
				
					SET yb_read_after_commit_visibility = 'relaxed';

SELECT customer_id, COUNT(*) 
FROM events
WHERE event_ts >= now() - interval '1 day'
GROUP BY customer_id;
				
			
        • β—‡ If these analytics run every few minutes/hours and aren’t customer-facing, a few missing seconds (max allowed clock skew to be precise (default of 500ms) (See: max_clock_skew_usec)) of writes is acceptable.
      • β–ͺ Background jobs + maintenance
        • β—‡ Database cleanup tools
        • β—‡ Validation passes
        • β—‡ Monitoring collectors
        • β—‡ Periodic reports not used for financial/audit purposes
    • ❌ When NOT to use relaxed
      • β–ͺ User-facing reads
      • β–ͺ APIs depending on strict correctness
      • β–ͺ Systems interacting with Kafka/CDC events
      • β–ͺ Any workload where β€œread-your-own-write” is required
      • β–ͺ Regulatory or audit reporting
      • β–ͺ Anything customers see directly
  • ● deferred: advanced (YugabyteDB 2024.2+)

    • β—‹ Introduced in YugabyteDB 2024.2.6.0-b94

    • β—‹ A mode that can defer the actual read time for both read and write transactions, helping avoid read restart errors.

    • β—‹ Designed to reduce restarts by delaying reads until safe

    • β—‹ Best suited for transactions that:

      • β–ͺ Can tolerate a small latency delay

      • β–ͺ Cannot tolerate a restart

    • β—‹ Guidance:
      • β–ͺ Treat as advanced unless your release notes explicitly endorse it for your version
      • β–ͺ Test thoroughly before using in production
      • β–ͺ Avoid using it globally… control it at the session level
πŸ§ͺ Side-by-Side Scenario: How Each Mode Behaves

You run this reporting query:

				
					SELECT customer_id, COUNT(*)
FROM orders
WHERE created_at >= current_date - interval '1 day'
GROUP BY customer_id;
				
			

Mode: strict

  • ● May raise: Restart read required

  • ● You retry the query

  • ● Guarantees no stale reads

Mode: relaxed

  • ● Query avoids restart

  • ● Result may miss a few very recent orders

  • ● Fine for internal dashboards or nightly batch jobs

Mode: deferred

  • ● Query will waitΒ for a safe timestamp

  • ● Avoids restarts while ensuring correctness

  • ● Latency is higher; requires careful testing

πŸ› οΈ Practical Recommendations

βœ”οΈ 1. Keep the cluster default: strict

    • This ensures all applications get strong consistency by default.

βœ”οΈ 2. Use relaxed only for safe, isolated workloads

    • ● Prefer session-level:
				
					SET yb_read_after_commit_visibility = 'relaxed';
				
			
    • ● Typical safe workloads:
      • β—‹ Index checks

      • β—‹ DBA maintenance tools

      • β—‹ Backfill jobs

      • β—‹ Large internal analytics

  • ● Try using the available transaction isolation levels before touching visibility settings
    • β—‹ READ COMMITTED (recommended first)
      • β–ͺ Greatly reduces restarts caused by retries without sacrificing correctness.
      • β–ͺ YugabyteDB will also retry automatically under REPEATABLE READ if the statement is the first statement in the transaction block.
    • β—‹ β—‹ SERIALIZABLE
      • β–ͺ Avoids all read-restart errors.
      • β–ͺ However, it effectively locks everything it reads, which can be very expensive for workloads that scan or read large volumes of data.
    • ● Use deferred only when recommended by release notes
      • β—‹ And keep it isolated to specific sessions.
🧭 Summary

In YugabyteDB, read-restart errors are a safety mechanism… not a flaw.

When clock-based ambiguity arises, the database protects correctness by asking the client to retry. With the introduction of yb_read_after_commit_visibility and the new deferred mode, you now have fine-grained control over how strictly the system enforces read-after-commit guarantees.

Keep strict for customer-facing and correctness-critical paths, and selectively relax visibility only for internal jobs or workflows that can tolerate brief staleness. Used thoughtfully, these settings let you reduce noise from read restarts while preserving the strong consistency guarantees that make YugabyteDB dependable at scale.

Special thanks to Piyush Jain, Staff Engineer @ YugabyteDB, for reviewing this tip for accuracy!

Have Fun!

One of the most popular swag items at AWS re:Invent: the Event Survival Kit... complete with hydration, first aid, mints, a door tag, a sleep mask, and more. A few lucky attendees even uncovered a Golden Ticket for a special prize! πŸ’›πŸŽŸοΈ