Two late goals saw QPR slip to their first defeat in six matches.
Birmingham struck twice in the final 10 minutes through Kristian Pedersen and substitute Alen Halilovic after Charlie Austin had put Rangers in front on the stroke of half-time.
Rangers were poor in the first half, unable to create much going forward or keep the ball on the ground as the visitors, playing into a low sun, struggled to deal with Birmingham’s direct style.
The hosts almost went ahead when Gary Gardner’s piledriver from just outside the box was superbly tipped wide by Seny Dieng.
Despite their laboured first-half display, Rangers took the lead with the only meaningful attack when Austin played in Todd Kane and then met a delightful cross from the full-back to fire home at the back post.
Birmingham went close to an equaliser early in the second half when Scott Hogan almost pounced on a loose ball in the box, only for Rangers to break clear and almost grab a second.
Chris Willock got free on the left flank and played in Stefan Johansen, who somehow blazed over from close range with just keeper Neil Etheridge to beat.
Rangers were much improved in the second half and looked well in control up until the final 10 minutes when Pedersen rose highest in the box to head home a long throw.
Three minutes later Halilovic won the game when he took advantage of Niko Hamalainen backing off from making a tackle and curled a delightful finish past Dieng.
QPR: (3-5-2) Dieng; Dickie, Cameron, Barbet; Kane, Ball, Johansen (Adomah 87), Willock (Field 55), Hamalainen; Austin (Dykes 55), Bonne (Kelman 87).
Subs not used: Lumley, Kakay, Bettache, Thomas, Chair.