Marco Asensio hit the winner in a 2-1 semi-final, first-leg victory at Bayern Munich on Wednesday.
The 22-year-old came off the bench to finish a counter-attack and complete the holders’ comeback win, giving Real the advantage for the return game in Madrid next Tuesday.
Bayern took the lead at the sold-out Allianz Arena through Joshua Kimmich, but Marcelo equalised just before the break.
Despite Bayern dominating possession and creating plenty of chances, Madrid claimed a sixth straight win, dating back to 2012, over the Bavarians in the Champions League knockout stage.
Real coach Zinedine Zidane pulled a surprise before kick-off by leaving both Gareth Bale and Karim Benzema out of the starting line-up.
Isco, who was replaced by Asensio at half-time, and Lucas Vazquez played either side of Cristiano Ronaldo, who had a subdued night up front in Munich.
The Portuguese failed to add to his tally of 15 Champions League goals this season, being denied a second-half strike by an offside flag, which would have made it 3-1.
James Rodriguez, who is on a two-year loan deal from Real, shone in Bayern’s midfield and found plenty of cracks in the Madrid defence.
However, this just was not Bayern’s night.
Both Thomas Mueller and Robert Lewandowski went agonisingly close with a string of chances.
The hosts suffered a blow with barely five minutes gone when Arjen Robben limped off to be replaced by Thiago Alcantara.
Bayern changed their system with right-back Joshua Kimmich moving up to plug the space on the right wing, which sparked the opening goal.
When Bayern goalkeeper Sven Ulreich played the ball down the right flank, James released Kimmich with a perfectly-timed pass in the 28th minute.
The Germany international raced clear and caught out Keylor Navas at his near post to stun Real.
Bayern suffered their second early injury blow when Jerome Boateng was replaced by Niklas Suele on 34 minutes — which is also bad news for Germany with the World Cup looming.
Real had a left-off when Ribery went one-on-one with Navas, but stumbled at the crucial moment.
Then from nothing, Marcelo conjured the equaliser on 44 minutes.
When Dani Carvajal headed the ball across the edge of the box, it landed at Marcelo’s feet and was in Bayern’s net milliseconds later after a fierce left-footed shot.
It was the Brazilian’s third Champions League goal this season after also scoring in the knock-out rounds against Paris Saint-Germain and Juventus.
Real escaped again when Navas failed to hold a Lewandowski header just before the half-time whistle and the ball bobbled away to safety.
It shows how far Bale and Benzema have dropped out of Zidane’s favour that Isco was replaced on the left wing by Asensio for the second half, but the move paid off.
Rafinha lost the ball in midfield after a Bayern attack, and Vazquez sprinted clear and put Asensio into space to curl past Ulreich on 57 minutes.
With 25 minutes left, Zidane threw on an extra attacker, as Benzema came on for injured right-back Carvajal.
Moments later Bayern came within inches of an equaliser when Navas denied Mueller with a reflex save.
In the final five minutes, Lewandowski beat Navas, but his floated shot flew just wide of the post to add to Bayern’s misery.