Mikel Oyarzabal put Spain ahead at the San Siro before Karim Benzema struck back moments later. Kylian Mbappe completed a second comeback at these finals for Les Blues, who secured their place in this final by coming from two down against Belgium.
After a tactical, nervy and tight contest for more than an hour, the game burst into life. A frustrated Paul Pogba, looking wound up after being booked for a stamp on Sergio Busquets, drove through midfield and eventually the ball found Theo Hernandez who cracked the ball against the bar.
Spain raced up the other end and took the lead with a fine show of strength from Oyarzabal before a brilliant low finish into the far corner past Hugo Lloris.
Benzema had barely had a sniff since the opening five minutes, when he had rounded Unai Simon in goal but saw his cut-back cleared, until he struck while Spanish fans were still celebrating the opener.
The Real Madrid striker collected the ball on the left and, cutting inside at the corner of the box, bent a wonderful strike into the far corner, with Simon getting a touch but unable to prevent it finding the back of the net.
Mbappe was also having a quiet night but was alert when he needed to be, racing onto a ball from Theo Hernandez to put him one-on-one with Simon. Mbappe showed wonderful composure to delay, throw in a step-over and finish past Simon.
VAR checked Mbappe’s goal for offside but it was allowed to stand despite the striker being in an offside position due to the slightest of touches from Spanish defender Eric Garcia.
Lloris made two fine late saves to deny Spain a leveller, stopping from Oyarzabal and Yeremi Pino.