SKIP LOCKED, and the queue table that scales

Two workers claiming with FOR UPDATE serialise, so adding workers adds no throughput — which is the thing a queue exists to provide.

START TRANSACTION;

SELECT id, payload FROM jobs
WHERE reserved_at IS NULL
ORDER BY id LIMIT 1
FOR UPDATE SKIP LOCKED;

UPDATE jobs SET reserved_at = NOW() WHERE id = ?;

COMMIT;
-- and then do the work, OUTSIDE the transaction

Keeping the transaction short is the half that gets skipped: doing the work inside it holds the lock and recreates the serialisation it was meant to remove. NOWAIT is the sibling that errors rather than skipping, which suits an interactive request that would rather fail than hang. The recovery timer for a worker that died mid-job is still yours to write, which is the argument for a real broker.