Why random access exists at all
Picture the moment your phone wakes up in a new city. It has read the synchronisation signal block, decoded the MIB and SIB1, and it now knows everything about the cell except one thing the cell does not yet know about it: timing. The UE has no uplink timing advance, no dedicated resources, no identity the scheduler recognises. It is, from the gNB's point of view, an anonymous transmitter sitting somewhere between zero and tens of kilometres away. Every other uplink channel in 5G NR — PUSCH, PUCCH, SRS — assumes the UE is already time-aligned to within a fraction of a cyclic prefix. Random access is the one procedure that does not assume that. It is the bootstrap.
The random access procedure solves four problems in one shot. It lets an uncoordinated UE announce its presence; it lets the gNB measure the round-trip delay and hand back a timing advance so the UE's later transmissions land inside the cyclic prefix; it hands the UE a first uplink grant so it can say who it is; and — because many UEs may try at once — it resolves contention so exactly one of them keeps the grant. Strip away the acronyms and RACH is just a politely structured shouting match: everyone who wants in shouts a code, the gNB shouts back “I heard code 37, here is when and where to talk,” and a final exchange settles who code 37 actually belonged to.
RACH is a busy reception desk with no appointments. Walk-ins (UEs) each say a numbered ticket phrase out loud (the preamble). The receptionist (gNB) calls back a ticket number with a time slot and a desk (the RAR grant). If two people happened to say the same ticket phrase at the same instant, only one will match the name written down at the desk — the other has to take a fresh ticket and try again. That last step is contention resolution.
Getting RACH right matters more than its airtime suggests. It is the gate every connection passes through: an idle-to-connected transition, a handover, a beam-failure recovery, an uplink that has gone out of sync — all of them run random access first. If RACH is mis-tuned, the symptom is not “slow RACH,” it is accessibility failures, dropped handovers and coverage holes that look like everything-else problems. That is why this article spends as much time on the counters and the optimization as on the message flow.
Where this lives in 3GPP. The procedure itself is in TS 38.321 (MAC) §5.1. The preamble waveform, formats and PRACH mapping are in TS 38.211 §6.3.3. The power control, RA-RNTI and timing rules are in TS 38.213 §7 and §8. The IEs you configure (RACH-ConfigCommon, RACH-ConfigGeneric, RACH-ConfigCommonTwoStepRA) are in TS 38.331. Keep those four open and you can trace any RACH question to its source.
The RACH map — triggers, CBRA vs CFRA, 4-step vs 2-step
Before the message-by-message walk-through, fix the taxonomy in your head, because half of all RACH confusion is people talking about different variants without saying so. Random access in NR is classified along two independent axes.
Axis 1 — contention-based (CBRA) vs contention-free (CFRA)
In contention-based random access the UE picks its preamble at random from a shared pool, so two UEs can collide and a contention-resolution step is mandatory. In contention-free random access the network has already handed this specific UE a dedicated preamble (via rach-ConfigDedicated in an RRC Reconfiguration, or a PDCCH order) — nobody else will use it, so there is no collision and no Msg4 contention step. CFRA is what handover and beam-failure recovery use, because the target already knows the UE is coming and wants the fastest, most reliable access possible.
Axis 2 — 4-step vs 2-step
This is the axis that defines the message count. 4-step is the classic Msg1–Msg2–Msg3–Msg4 flow. 2-step (introduced in Release 16) folds Msg1+Msg3 into a single MsgA and Msg2+Msg4 into a single MsgB. The two axes combine: you can have 4-step CBRA, 4-step CFRA, 2-step CBRA and 2-step CFRA. The table below is the whole solution space.
| Variant | Preamble | Messages | Contention step? | Typical trigger |
|---|---|---|---|---|
| 4-step CBRA | random, from shared pool | Msg1·2·3·4 | Yes (Msg4) | Initial access from idle, RRC re-establishment, UL data with no SR/PUCCH |
| 4-step CFRA | dedicated | Msg1·2 (no 3/4) | No | Handover, beam-failure recovery, PDCCH-ordered RA |
| 2-step CBRA | random, from shared pool | MsgA·MsgB | Within MsgB (successRAR) | Small cells, NR-U, low-latency / small-data access |
| 2-step CFRA | dedicated | MsgA·MsgB | No | Handover in good coverage (FR2), latency-critical |
Before going deeper, watch the whole 4-step handshake play out once. The diagram below animates the four messages in order — uplink shots from the UE in amber, downlink answers from the gNB in violet — so the sequence and direction of every message is unmistakable.
The seven things that trigger random access
TS 38.321 §5.1.1 lists the events that kick off the procedure. Worth memorising, because the trigger changes what the UE puts in Msg3 and whether CFRA is even possible:
- Initial access from RRC_IDLE — the cold start; Msg3 carries
RRCSetupRequest. - RRC re-establishment after radio-link failure — Msg3 carries
RRCReestablishmentRequest. - Handover — the target cell usually pre-assigns a dedicated preamble (CFRA).
- DL data arrival while uplink is “non-synchronised” — the gNB sends a PDCCH order to make the UE do RACH and regain timing.
- UL data arrival while non-synchronised, or when no PUCCH scheduling-request resource is configured.
- SR failure — scheduling requests went unanswered up to the configured maximum.
- Beam failure recovery — the serving beam died; RACH (often CFRA on a recovery preamble) requests a new one.
- (Rel-16+) Request for Other SI, transition out of RRC_INACTIVE, and timing-advance re-acquisition.
The mental model that never fails you. 4-step is “knock, get told where to sit, introduce yourself, get acknowledged.” 2-step is “knock-and-introduce-yourself in the same breath, then get acknowledged.” CFRA is “you were expected, your seat has your name on it.” Everything below is just the engineering of those three sentences.
Msg1 part 1 — the preamble: Zadoff–Chu, roots and Ncs
Msg1 is a single preamble transmitted on PRACH. The preamble is not data — it carries exactly log2(64) = 6 bits of information: which of 64 preambles the UE chose. Everything clever about Msg1 is in the waveform, because that waveform has to be detectable by a receiver that does not yet know the UE's timing, at SNRs where ordinary data would be undecodable.
Why Zadoff–Chu
NR preambles are Zadoff–Chu (ZC) sequences. A root ZC sequence of odd length L is defined as:
ZC sequences have two magical properties for this job. First, constant amplitude — the time-domain signal has a low peak-to-average power ratio, so the UE's power amplifier can drive it hard at the cell edge. Second, perfect (zero) cyclic autocorrelation — a ZC sequence correlated against a cyclically shifted copy of itself produces a sharp single peak at exactly the shift offset. That is the entire detection trick: the gNB correlates the received signal against each root, and the position of the correlation peak tells it both which preamble and how late it arrived — i.e. the round-trip delay it will turn into a timing advance.
From one root to 64 preambles — cyclic shifts and Ncs
A cell needs exactly 64 preambles. Rather than use 64 different roots (which correlate imperfectly against each other), NR generates many preambles from a single root by applying cyclic shifts. Each shift is a multiple of Ncs, the “zero-correlation zone” spacing:
Ncs is the single most physically meaningful PRACH parameter you will tune, because it encodes the cell radius. The zero-correlation zone must be wider than the largest round-trip delay you expect, plus delay spread, or two UEs at different distances using shifts of the same root will alias onto each other's correlation windows. Bigger cell → bigger required Ncs → fewer shifts per root → more roots consumed per cell. You set Ncs indirectly through zeroCorrelationZoneConfig (values 0–15), which indexes a table in TS 38.211 (the table chosen depends on preamble format and restricted-set type).
Here is why the zero-correlation property matters in practice. When the gNB correlates the received signal against a root sequence, the output is flat noise except at one sharp peak — and the position of that peak is the round-trip delay, which becomes the timing-advance command. Watch the detector sweep and lock onto it:
Restricted sets — the high-speed problem
At high Doppler (think a UE on a 350 km/h train) the frequency offset rotates the ZC correlation peak into a spurious secondary peak, which the receiver can mistake for a different shift — a false alarm or a wrong timing estimate. NR fixes this with restricted sets: restrictedSetConfig = unrestricted, restrictedSetTypeA or restrictedSetTypeB. Restricted sets blacklist the cyclic shifts that would alias under Doppler, at the cost of fewer usable shifts per root. Use unrestricted for normal cells; switch to Type A/B only on genuinely high-speed cells (rail, highway), and expect to consume more roots.
Preamble formats — long vs short
The format sets the subcarrier spacing, the sequence length, how many times the ZC sequence repeats, and the cyclic-prefix length — which together fix the maximum cell radius and the robustness. There are two families.
Long preambles (LRA = 839, FR1 only)
| Format | SCS | ZC repetitions | Max cell radius (approx.) | Use |
|---|---|---|---|---|
| 0 | 1.25 kHz | 1 | ≈ 14.5 km | Default macro |
| 1 | 1.25 kHz | 2 (long CP) | ≈ 100 km | Very large / rural macro |
| 2 | 1.25 kHz | 4 | ≈ 22 km | Coverage-limited (repetition gain) |
| 3 | 5 kHz | 4 | ≈ 14.5 km | High-speed (wider SCS tolerates Doppler) |
Short preambles (LRA = 139, FR1 & FR2)
Short formats use the same subcarrier spacing as data (15/30 kHz in FR1, 60/120 kHz in FR2, plus 480/960 kHz for FR2-2), so the PRACH slot lines up neatly with the data numerology and the gNB receiver is simpler. They come in two sub-families: A-formats (A1/A2/A3) have a cyclic prefix sized for back-to-back occasions, and B-formats (B1–B4) use a shorter CP for tighter packing. The number after the letter is the count of ZC repetitions: more repetitions → more coverage, fewer occasions per slot. Format B4 (12 symbols) is the most robust short format and is common in FR2 cell-edge configurations; C0/C2 are the long-CP short formats for larger short-preamble cells.
Format selection is a coverage decision, not a default. Pick the shortest format that still closes the uplink link budget at your cell edge. Over-provisioning (e.g. Format 1 or B4 everywhere) wastes PRACH airtime and reduces the number of RACH occasions, which raises collision probability under load — you trade a coverage problem for an accessibility problem.
PRACH configuration & RACH occasions — the SSB→RO map
A UE cannot transmit a preamble whenever it likes. PRACH is confined to specific time-frequency RACH occasions (ROs), and those ROs are mapped to SSB beams so that a preamble in a given RO tells the gNB which downlink beam the UE prefers. This mapping is the heart of beam-based access and the part engineers most often get subtly wrong.
The time domain — prach-ConfigurationIndex
One number, prach-ConfigurationIndex (0–255), selects a row of TS 38.211 Table 6.3.3.2 that fixes the preamble format, in which system frames PRACH appears (the PRACH configuration period — every frame, every other frame, etc.), the subframe/slot numbers, the starting symbol, the number of PRACH slots within a 60 kHz slot, and the number of time-domain ROs per PRACH slot. Choosing this index sets how often RACH opportunities recur — the lever for RACH capacity in the time domain.
The frequency domain — msg1-FDM and msg1-FrequencyStart
msg1-FDM (one/two/four/eight) sets how many ROs sit side by side in frequency in the same time instant — multiplying RACH capacity. msg1-FrequencyStart places the PRACH frequency block as an offset from the bottom of the initial uplink BWP. Together they decide the PRACH frequency footprint inside the carrier.
The SSB→RO mapping — ssb-perRACH-OccasionAndCB-PreamblesPerSSB
This single IE does two jobs at once. Its first part says how many SSBs map to each RACH occasion — values from oneEighth (one SSB spreads over 8 ROs, used when you have many beams) up to sixteen (16 SSBs share one RO). Its second part says how many contention-based preambles per SSB are carved out of the 64. The UE first measures the SSBs, picks the strongest one above rsrp-ThresholdSSB, finds the RO(s) that SSB maps to, and only then chooses a preamble. That is how a contention-based preamble still carries beam information.
| Parameter (TS 38.331) | Range / values | What it controls |
|---|---|---|
prach-ConfigurationIndex | 0–255 | Format + time-domain RO pattern (frame/slot/symbol) |
msg1-FDM | one, two, four, eight | Frequency-multiplexed ROs per time instant |
msg1-FrequencyStart | 0–(NBWP−1) PRB | PRACH frequency offset in the UL BWP |
zeroCorrelationZoneConfig | 0–15 | Ncs → cyclic-shift spacing → cell radius |
restrictedSetConfig | unrestricted / A / B | High-speed (Doppler) shift restriction |
ssb-perRACH-OccasionAndCB-PreamblesPerSSB | oneEighth…sixteen + N | SSB→RO ratio & CB preambles per SSB |
prach-RootSequenceIndex | 0–837 (L=839) / 0–137 (L=139) | Logical root the cell starts from |
rsrp-ThresholdSSB | RSRP level | Min SSB quality the UE will RACH against |
Build a PRACH configuration and watch it light up
Drag prach-ConfigurationIndex, msg1-FDM and Ncs and see the RACH occasions, SSB→RO mapping and per-cell preamble budget redraw in real time — on the same engine that powers this article's diagrams. Lifetime access — ₹999 / $9.99.
Msg1 part 2 — preamble selection & power ramping
With the configuration understood, here is exactly what the UE's MAC does the instant random access is triggered, step by step from TS 38.321 §5.1.2–5.1.3.
- Select an SSB. Measure all SSBs; pick one whose RSRP exceeds
rsrp-ThresholdSSB. If none qualifies, pick any SSB (the UE still has to try). - Select a preamble group. For CBRA, the 64 preambles may be split into Group A and Group B. The UE chooses Group B if its Msg3 will be large and its path loss is low enough (controlled by
ra-Msg3SizeGroupA,messagePowerOffsetGroupB,numberOfRA-PreamblesGroupA). This lets the gNB infer the Msg3 size from the preamble group and grant accordingly. - Select a preamble at random from the chosen group mapped to the chosen SSB. For CFRA, use the assigned dedicated preamble — no randomness.
- Determine the RACH occasion that the selected SSB maps to.
- Set the transmit power (below) and transmit.
Open-loop power and the ramping ladder
The UE has never heard back from this cell, so it cannot do closed-loop power control. It estimates path loss from the SSB it just measured and aims for a target received power the gNB published:
PPRACH = min( PCMAX, PREAMBLE_RECEIVED_TARGET_POWER + PL )
If the attempt fails — no matching RAR inside ra-ResponseWindow, or contention not resolved — the UE increments PREAMBLE_POWER_RAMPING_COUNTER and retransmits a fraction of a dB louder. It keeps climbing this ladder until it succeeds or hits preambleTransMax attempts, at which point the MAC reports a random-access problem to RRC (which, for initial access, means the cell selection failed and the UE looks elsewhere).
The counter does not ramp when you switch beams. If the UE re-selects a different SSB between attempts (because the first beam faded), PREAMBLE_POWER_RAMPING_COUNTER is held, not incremented — otherwise the open-loop estimate for the new beam would be polluted by ramping done against the old one. This subtlety is why naïve “average preamble attempts” counters can mislead in beamformed cells.
powerRampingStep (0/2/4/6 dB) until success or preambleTransMax.| Power / retry parameter | Typical range | Engineering effect |
|---|---|---|
preambleReceivedTargetPower | −202…−60 dBm (step 2), e.g. −110 | Target Rx power at gNB; too low → Msg2 misses, too high → UL interference |
powerRampingStep | 0, 2, 4, 6 dB | How fast the UE climbs; bigger = faster access, more interference overshoot |
preambleTransMax | n3,n4,n5,n6,n7,n8,n10,n20,n50,n100,n200 | Max attempts before declaring failure |
ra-ResponseWindow | sl1…sl80 (slots) | How long the UE waits for Msg2; too short → false Msg2 failures |
ra-ContentionResolutionTimer | sf8…sf64 (subframes) | How long the UE waits for Msg4 before declaring contention lost |
Msg2 — RA-RNTI and the 27-bit RAR grant
The gNB detected a preamble. Now it answers with the Random Access Response. Msg2 is a PDSCH transmission scheduled by a PDCCH whose CRC is scrambled with a special identity the UE can compute on its own: the RA-RNTI. This is elegant — the UE doesn't have an identity yet, so the network derives a temporary one purely from when and where the preamble was sent.
The UE only listens for a PDCCH scrambled with its RA-RNTI, during ra-ResponseWindow, starting a fixed offset after the preamble. When it finds one, it reads the RAR PDSCH. A RAR PDSCH can contain multiple RAR subPDUs — one per preamble the gNB heard in that occasion — each tagged with a RAPID (Random Access Preamble Identifier). The UE scans for the RAPID matching the preamble it sent. Match found → this RAR is for me. No match → keep waiting, or fail the window.
Inside one RAR subPDU
Three fields do the real work. The Timing Advance Command (12 bits) tells the UE how much to advance its uplink clock so Msg3 lands inside the gNB's receive window. The UL Grant (27 bits) schedules Msg3 on PUSCH — frequency-hopping flag, frequency and time allocation, modulation/coding, a power-control command and a CSI-request bit. The TC-RNTI (Temporary C-RNTI, 16 bits) is the identity the UE will use for Msg3 and until contention resolution promotes it (or not) to a real C-RNTI.
For CFRA, this is the finish line. Because a contention-free UE used a dedicated preamble, a matching RAR means the access succeeded — there is no Msg3/Msg4. That is why handover and beam-failure recovery feel instant: they are two-message procedures (Msg1+Msg2) with a pre-known identity.
Msg3 — the first scheduled uplink & the UE identity
Msg3 is the first time the UE transmits scheduled data on PUSCH using the grant from the RAR — and now timing-aligned, so it actually lands cleanly. Its job is to carry the UE's identity so the network can finish the handshake. What it carries depends on why RACH was triggered:
| Trigger | Msg3 payload (CCCH/DCCH) | Identity mechanism |
|---|---|---|
| Initial access (idle→connected) | RRCSetupRequest (CCCH SDU) | 48-bit CCCH SDU echoed back in Msg4 |
| RRC re-establishment | RRCReestablishmentRequest | CCCH SDU echoed in Msg4 |
| RRC resume (from INACTIVE) | RRCResumeRequest | resume identity + CCCH echo |
| Connected UE (already has C-RNTI) | C-RNTI MAC CE | PDCCH to C-RNTI resolves contention |
Msg3 is HARQ-protected. If it isn't decoded, the gNB schedules a retransmission with a DCI format 0_0 addressed to the TC-RNTI, and the UE combines retransmissions. Msg3 can also use frequency hopping (the hop flag in the RAR grant) to get a diversity gain on this critical, low-SINR transmission. Because Msg3 is the cell-edge UE's hardest uplink, its reliability is often the real bottleneck of accessibility — not Msg1.
“Operators chasing accessibility almost always blame Msg1 coverage. Pull the per-step counters and the truth is usually Msg3: the preamble got through, the RAR was sent, and then the cell-edge PUSCH collapsed.”
— a pattern you will see again and again in RACH KPIsMsg4 — contention resolution
Here is the problem Msg4 exists to solve. In CBRA, several UEs can pick the same preamble in the same RACH occasion. The gNB hears one preamble, sends one RAR, and now multiple UEs all think the grant is theirs. They all transmit Msg3 on the same PUSCH resource — usually one survives the collision and is decoded. Contention resolution is how the network tells the colliding UEs which one won.
Two mechanisms, depending on what Msg3 carried:
- Msg3 carried a C-RNTI MAC CE (a connected UE): the gNB sends a PDCCH addressed to that C-RNTI. The UE that owns the C-RNTI sees its own PDCCH → contention resolved, done.
- Msg3 carried a CCCH SDU (initial access): the gNB sends a UE Contention Resolution Identity MAC CE in Msg4 that echoes the first 48 bits of that CCCH SDU. The UE compares: if the echoed bits equal what it sent, it won; if not, it lost.
ra-ContentionResolutionTimer expires; it ramps power and starts a fresh attempt.The ra-ContentionResolutionTimer starts when Msg3 is transmitted. If the UE doesn't get a matching PDCCH (C-RNTI case) or a matching identity (CCCH case) before it expires, the attempt failed: the UE flushes the HARQ buffer for Msg3, increments the preamble counter, backs off a random time (ra-msg3-Backoff / the Backoff Indicator the gNB may send in Msg2), and starts again from preamble selection. The Backoff Indicator is the network's load-shedding valve: under congestion the gNB tells UEs to wait longer before retrying, spreading the load.
When contention is resolved on an initial access, Msg4 also carries the RRCSetup that promotes the UE into RRC_CONNECTED, and the TC-RNTI is promoted to the UE's C-RNTI. The bootstrap is complete: from anonymous transmitter to fully scheduled, time-aligned connection in four messages.
2-step RACH — MsgA, MsgB and fallback
Every round trip in 4-step costs latency — and in unlicensed spectrum (NR-U), every round trip also costs a fresh listen-before-talk gamble. Release 16 introduced 2-step RACH to cut the four messages to two. The idea is bold: send the preamble and the payload that would have been Msg3 together, before you have any timing advance at all.
MsgA = preamble + PUSCH payload
MsgA has two parts transmitted close together: a PRACH preamble (exactly like Msg1, drawn from a 2-step preamble pool) followed by a PUSCH payload that carries what Msg3 would have carried (e.g. the RRCSetupRequest CCCH SDU, or a C-RNTI MAC CE). The PUSCH part rides on a pre-configured resource called the MsgA PUSCH Occasion, associated with the preamble the UE chose. Because there is no timing advance yet, the MsgA PUSCH uses a generous guard period and is dimensioned for the cell's expected delay spread.
MsgB = successRAR or fallbackRAR
The gNB's response, MsgB, is scrambled with the MSGB-RNTI (computed like RA-RNTI but offset into a separate range so 2-step and 4-step responses never alias). MsgB can be one of two things:
- successRAR — the gNB decoded both the preamble and the PUSCH payload. Contention is already resolved (the payload identified the UE), so MsgB carries the contention-resolution identity, the C-RNTI and a timing advance. Access complete in one round trip.
- fallbackRAR — the gNB heard the preamble but could not decode the PUSCH payload (often because the unknown propagation delay corrupted it). MsgB then looks just like a 4-step RAR: it carries a RAPID, a TA command and a Msg3 grant. The UE falls back to 4-step, sends Msg3 on the granted resource, and finishes with contention resolution. Latency is back to two round trips, but the attempt isn't wasted.
2-step configuration & when to switch
2-step has its own parameter block (RACH-ConfigCommonTwoStepRA): msgA-PreambleReceivedTargetPower, msgA-PUSCH-Config (the PUSCH occasions, DMRS, MCS), msgA-CB-PreamblesPerSSB, msgB-ResponseWindow, preambleTransMax for 2-step, and crucially msgA-RSRP — the threshold that decides, when both 2-step and 4-step are configured, which one a UE uses. Good-coverage UEs (RSRP above msgA-RSRP) use 2-step; cell-edge UEs use 4-step, because their large unknown delay would likely corrupt the MsgA PUSCH and force a fallback anyway.
| Dimension | 4-step | 2-step |
|---|---|---|
| Messages / round trips | 4 / 2 | 2 / 1 (best case) |
| Latency | Higher | Lower |
| UL resource cost | Lower (Msg3 only after grant) | Higher (PUSCH sent speculatively) |
| Robust to large unknown delay | Yes (TA before Msg3) | No (falls back) |
| Best fit | Macro, cell edge, congestion | Small cells, FR2, NR-U, low latency |
| Response RNTI | RA-RNTI | MSGB-RNTI |
Run MsgA / MsgB and trigger a fallback yourself
Step through 2-step RACH frame by frame, force a PUSCH-payload failure, and watch the gNB drop you into the 4-step path with a fallbackRAR — the clearest way to understand why msgA-RSRP matters. Lifetime access — ₹999 / $9.99.
Failure analysis — the four places RACH breaks
Now the part that pays the bills. When accessibility KPIs dip, RACH is the first suspect, and the procedure breaks in exactly four places. Knowing which one tells you which knob to turn.
FAIL 1 — Msg1/Msg2 (no RAR)
The gNB never detected the preamble, or the UE never decoded the RAR in ra-ResponseWindow. Causes: downlink/uplink coverage hole; wrong prach-ConfigurationIndex (UE and gNB disagree on where PRACH is); root-sequence / Ncs collision with a neighbour (the gNB correlates a neighbour's UE as a ghost); PRACH-band interference; or ra-ResponseWindow set too short so the UE gives up before a (slightly late) RAR arrives.
FAIL 2 — Msg3 lost
RAR decoded, but the scheduled Msg3 PUSCH was never received. This is the cell-edge killer: Msg3 is a low-SINR uplink and if the link budget doesn't close, no amount of preamble tuning helps. Also caused by a bad timing-advance estimate (Msg3 lands outside the cyclic prefix) or HARQ retransmissions exhausting before success. Fixes live in uplink coverage, Msg3 MCS/repetition and TA accuracy — not in PRACH.
FAIL 3 — contention lost
Two UEs collided, one won, the loser's ra-ContentionResolutionTimer expired. A little of this is normal. A lot of it means too few preambles/ROs for the offered load — collision probability rises sharply as the per-RO preamble pool fills. The fix is PRACH dimensioning (more ROs via msg1-FDM or a denser prach-ConfigurationIndex, more CB preambles per SSB) and Backoff-Indicator tuning under congestion.
FAIL 4 — ramp exhaustion
The UE climbed the whole power ladder and still failed preambleTransMax times. This is the symptom of 1–3 persisting, plus possibly a too-low preambleReceivedTargetPower or too-small powerRampingStep (the UE never gets loud enough fast enough). It is what the user experiences as “no service” or a failed call setup.
Counters, KPIs & the optimization playbook
You localise RACH failures with per-step PM counters. Every vendor exposes equivalents of the same logical set — the names differ (Ericsson pmRadioRa… families, Huawei N.RA.… / RACH measurement counters, Nokia RACH_…, ZTE NR RA counters) but the meaning is universal. Map your vendor's names onto this logical model and the maths below is portable.
| Logical counter | Counts | Exposes |
|---|---|---|
| Preambles received (CBRA / CFRA, by group A/B) | preambles the gNB detected | PRACH load & collision pressure |
| RARs transmitted (Msg2) | responses sent | Msg1→Msg2 yield |
| Msg3 received / decoded | successful first scheduled UL | cell-edge UL health (FAIL 2) |
| Contention resolutions sent (Msg4) | completed handshakes | collision rate (FAIL 3) |
| Avg / distribution of preamble attempts | ramping depth | coverage & power tuning |
| RA failures / ramp-outs | preambleTransMax hits | accessibility loss (FAIL 4) |
The KPIs that matter
Msg2 success rate = (RARs sent) / (preambles received)
Msg3 success rate = (Msg3 decoded) / (RARs sent)
Contention resolution rate = (Msg4 success) / (Msg3 decoded)
Avg preamble Tx attempts = Σ(attempts) / (successful accesses)
The optimization playbook
| Symptom (from counters) | Most likely cause | Action |
|---|---|---|
| Low Msg2 rate, low load | Coverage / target power too low / Ncs collision | Raise preambleReceivedTargetPower; pick a longer/repeated format; re-plan roots & Ncs; check PRACH interference |
| Low Msg2 rate, high load | Too few ROs / preambles — collisions look like misses | Increase msg1-FDM, denser prach-ConfigurationIndex, more CB preambles/SSB |
| Good Msg2, poor Msg3 | Cell-edge UL / bad TA / HARQ exhaustion | Msg3 repetition & robust MCS; verify TA; improve UL link budget; check ra-ResponseWindow timing |
| High contention loss | Preamble pool too small for demand | More ROs/preambles; tune Backoff Indicator; split Group A/B by Msg3 size |
| High avg attempts | Ramp too slow / target too low | Increase powerRampingStep; raise target power; reconsider format |
| RACH OK but latency high | 4-step round trips dominate | Enable 2-step with a sensible msgA-RSRP split |
| High-speed cell, sporadic ghosts | Doppler aliasing of cyclic shifts | Switch restrictedSetConfig to Type A/B |
| Large rural cell, edge fails | RTT exceeds Ncs zero-corr zone | Long format 1, larger Ncs, accept fewer shifts/root |
The golden rule of PRACH dimensioning. Capacity (more ROs/preambles to cut collisions) and coverage (longer formats, bigger Ncs) both consume the same finite PRACH airtime and root budget. You cannot maximise both — size the cell for its actual radius and offered load, and re-check after every coverage or load change. Over-dimensioning PRACH steals PUSCH capacity for no benefit.
Developer & test view — RRC IEs, srsRAN/OAI, logs
If you build, test or simulate RACH rather than optimise a live network, here is where it surfaces.
Where the config lives in RRC
The cell broadcasts RACH config in SIB1 inside ServingCellConfigCommon → uplinkConfigCommon → initialUplinkBWP → rach-ConfigCommon. The key sub-structures:
RACH-ConfigCommon—rach-ConfigGeneric(the parameters above:prach-ConfigurationIndex,msg1-FDM,msg1-FrequencyStart,zeroCorrelationZoneConfig,preambleReceivedTargetPower,preambleTransMax,powerRampingStep,ra-ResponseWindow), plusssb-perRACH-OccasionAndCB-PreamblesPerSSB,ra-ContentionResolutionTimer,rsrp-ThresholdSSB,restrictedSetConfig,prach-RootSequenceIndex.RACH-ConfigCommonTwoStepRA— the 2-step block (msgA-*,msgB-ResponseWindow,msgA-RSRP).RACH-ConfigDedicated— CFRA assignment (dedicated preamble index + RO), delivered in an RRC Reconfiguration for handover/BFR.
Reading it in an open-source stack
In srsRAN Project or OpenAirInterface, the gNB config file sets prach_config_index, prach_root_sequence_index, zero_correlation_zone, msg1_frequency_start, preamble_rx_target_pw, etc.; the UE logs walk the exact MAC states — RA procedure init, preamble Tx with the chosen index and power, RAR reception with the decoded RAPID and TA, Msg3 Tx, and contention resolution outcome. A typical UE-side trace reads like the message flow in this article, one line per state transition. To read it from the air, decode the PDCCH for the RA-RNTI you expect (compute it with the formula in Chapter 6) and you'll find the RAR PDSCH that follows.
A debugging shortcut. If a UE seems to send Msg1 but never proceeds, compute the RA-RNTI by hand from the occasion it used and confirm the gNB is transmitting a PDCCH with that exact RNTI in the response window. A mismatch (wrong slot index, wrong f_id, NUL vs SUL confusion) means the UE is listening for the wrong identity — a classic and easily-missed integration bug.
Master the entire 5G NR physical layer
100+ interactive topics — frame structure, SSB & cell search, RACH (4-step & 2-step), beam management, HARQ, channel coding, scheduling, measurements and more — built for engineers who want to understand, not memorise. RACH alone has live PRACH, RA-RNTI and contention labs. ₹999 / $9.99 one-time, lifetime access.
Enrol in the 5G PHY LabFrequently asked questions
What is the difference between 4-step and 2-step RACH?
4-step uses Msg1 (preamble), Msg2 (RAR with TA + grant), Msg3 (identity), Msg4 (contention resolution). 2-step folds Msg1+Msg3 into one MsgA (preamble + PUSCH payload) and Msg2+Msg4 into one MsgB (successRAR completes it, or fallbackRAR drops you back to 4-step at Msg3). 2-step halves the round trips at the cost of speculative uplink resources.
How is RA-RNTI calculated?
RA-RNTI = 1 + s_id + 14×t_id + 14×80×f_id + 14×80×8×ul_carrier_id, from the symbol, slot, frequency index and carrier of the PRACH occasion. The UE computes it itself and uses it to find its RAR. 2-step uses the parallel MSGB-RNTI.
What does the RAR contain?
A RAPID (which preamble was heard), a 12-bit Timing Advance Command, a 27-bit uplink grant scheduling Msg3, and a 16-bit TC-RNTI.
What is contention resolution and why is it needed?
Multiple UEs can pick the same preamble in the same occasion. Contention resolution decides who owns the grant: a PDCCH to the UE's C-RNTI (if Msg3 carried a C-RNTI MAC CE), or a Msg4 MAC CE echoing the first 48 bits of the UE's CCCH SDU (initial access). The loser's ra-ContentionResolutionTimer expires and it retries.
How does preamble power ramping work?
The UE targets preambleReceivedTargetPower + DELTA_PREAMBLE + (counter−1)×powerRampingStep plus path loss, capped at PCMAX. Each failed attempt steps the counter (and power) up, until success or preambleTransMax. The counter holds (doesn't ramp) when the UE switches SSB beams.
What are the main RACH failure points and how do I troubleshoot them?
Four: no RAR (coverage/config/Ncs collision/interference), Msg3 lost (cell-edge UL/TA/HARQ), contention lost (too few preambles/ROs for the load), and ramp exhaustion (the persistent symptom). Localise with per-step counters, then fix with PRACH dimensioning, root planning, power tuning or timer settings — see the playbook in Chapter 11.
When should I use 2-step instead of 4-step?
Use 2-step where latency dominates and timing advance is small or known: small cells, FR2, NR-U, low-latency/small-data. Use 4-step for macro, cell edge and congestion. Most networks configure both and split by msgA-RSRP.
That is the whole bootstrap: from an anonymous UE shouting a Zadoff–Chu code into the void, through timing advance, a grant and a contention fight, to a fully scheduled connection — in four messages, or two. Master RACH and you've mastered the gate every 5G connection walks through. The fastest way to make it stick is to watch it: open the 4-step and 2-step labs and run a preamble through every state yourself.