Madrid were toothless in their defeat at Rayo Vallecano but took the lead in opportunistic style after two minutes, Brahim Diaz dispossessing Santi Cazorla midway through the visitors’ half before Mariano wriggled between two defenders and rolled a low shot beyond Andres Fernandez.
The equaliser came nine minutes later and in almost identical fashion, with Casemiro the player to concede possession cheaply to Alvaro Gonzalez before Moreno hooked the ball just inside the post with Thibaut Courtois well beaten.
Dani Carvajal crashed a shot onto the post as Madrid looked to restore their lead quickly but they had to wait until five minutes before half-time when Marcelo’s drive got tangled up in the legs of Samuel Chukwueze and Vallejo was on hand to tap the ball past the stranded Fernandez.
Four minutes after the interval, Mariano timed his run perfectly as he arrived at the far post to meet Carvajal’s low cross and slam the ball into the net.
Marcelo looked certain to score after his mazy dribble down the left flank took him into the box where Fernandez made an impressive one-handed save to parry his side-footed strike away from danger.
Villarreal refused to go down without a fight and their determination to grab a share of the points earned them a late consolation when Moreno played in Costa, who had time and space to pick his spot and beat Courtois with what proved to be the last chance of the game.
What does it mean? Final day drama unlikely
By the time Real Madrid return to the Bernabeu for their final-day clash with Real Betis, it is likely that second place will be beyond them, despite this victory. Villarreal, meanwhile, should have enough of a margin to ensure their top-flight status.
Mariano eases reliance on Benzema
If Mariano can turn in more performances like this one, Zidane will feel far more comfortable about his attacking options when Benzema is not available – and perhaps will not hesitate to part ways with Bale.
Cazorla error settles Madrid’s nerves
Villarreal look to Cazorla for experience and composure but the 34-year-old got caught out early on, making a mistake that helped Madrid ease into the game.