Two high-quality opponents produced numerous uncharacteristic errors, with Joshua Kimmich beating Real goalkeeper Keylor Navas at his near post to give Bayern the lead.
Marcelo equalised after 44 minutes, after Bayern had lost winger Arjen Robben and defender Jerome Boateng to injury.
Half-time substitute Marco Asensio struck after 57 minutes, capitalising on Rafinha’s sloppy pass, to give Zinedine Zidane’s men the advantage ahead of next week’s second leg at the Bernabeu.
Real’s sixth consecutive win over Bayern means the German champions must score at least twice and overcome the away goals advantage to have any hope of denying 12-time European champions Real’s progress to next month’s final in Kiev.
Last season, the teams — winners of four of the last five European Cups — met at the quarter-final stage, with Real winning 6-3 and Cristiano Ronaldo scoring five of the goals.
Bayern kept Ronaldo quiet on this occasion — the Portuguese star netted in the second half, but the strike was ruled out for handball — but their chances were hampered, as Robben departed after just eight minutes.
Bayern made light of the blow, as James Rodriguez, playing against his parent club, found rampaging right-back Kimmich in acres of space, exploiting the space Marcelo had vacated.
Instead of playing the ball into the centre of the area, Kimmich went for goal and was rewarded for his audacity, as Keylor Navas was found wanting.
Navas was also culpable for a Juventus goal in the quarter-final and his error will lead to heightened speculation that Real are in the market for a new goalkeeper this summer. Bayern lost Boateng, but had chances. Franck Ribery’s touch let him down as the Real defence opened up and Mats Hummels volleyed over as Robert Lewandowski headed on a corner.
Real reacted, levelling after a deep cross from left to right was headed back by Dani Carvajal and fell for Marcelo on the edge of the area. The Brazil full-back struck the ball low across Sven Ulreich to equalise.
Bayern still had chances, with Lewandowski heading straight at Navas, who gathered at the second attempt and Thomas Muller was off balance when he attempted to glance another Lewandowski header goalwards, the ball going wide. Ribery tried to engineer another Bayern goal, but a touch from Raphael Varane took the ball away from Muller.
Asensio, on for the ineffective Isco, punished Bayern for Rafinha’s misplaced pass. Lucas Vazquez played in Asensio and the replacement kept his composure to net.
Ribery was denied by Navas and then Real lost Carvajal through injury. Karim Benzema came on in his place, with Vazquez moving to right-back.
Bayern almost exploited the defensive uncertainty, when Kimmich’s cross was headed down by Javi Martinez.
The ball went towards Muller three yards out, but it would not sit for him and Real scrambled clear. Ribery then ran at Vazquez, firing narrowly wide.
Bayern should have levelled after 88 minutes. Corentin Tolisso played in Lewandowski, but he clipped the ball wide when it appeared easier to score, as Real enjoyed a third successive win at the Allianz Arena.
Ulreich, Kimmich, Boateng (Sule 34), Hummels, Rafinha, Javi Martinez (Tolisso 75), Robben (Thiago 8), Muller, Rodriguez, Ribery, Lewandowski.
Navas, Carvajal (Benzema 66), Sergio Ramos, Varane, Marcelo, Modric, Casemiro (Kovacic 83), Kroos, Lucas, Ronaldo, Isco (Asensio 46).
Bjorn Kuipers (Oldenzaal).