Sergio Ramos’ penalty after the lively Vinicius Jr was fouled gave the visitors the lead. Karim Benzema doubled their advantage before Mikel Merino’s strike set up a tense finale.
There was controversy when substitute Adnan Januzaj thought he had made it 1-1 with a strike from outside the area but it was ruled out for a Merino offside. Merino did not get a touch but the officials deemed he was blocking goalkeeper Thibaut Courtois’ view, so interfering with play.
Their sense of grievance grew when moments later Benzema controlled a Federico Valverde cross with his shoulder before firing home. The goal stood after a video assistant referee review for handball.
Real Madrid looked comfortable at that stage but Merino rifled a shot in via the underside of the crossbar, after a cross from substitute Roberto Lopez, to keep the closing minutes interesting.
The visitors’ biggest problem from the game came when Ramos was injured soon after his goal and needed an ice pack on his leg in the stands.
Madrid – who have only won one La Liga title since 2012 – are now eight victories away from winning the league.
Barcelona host Athletic Bilbao on Tuesday with Real Madrid at home to Mallorca the next day.