Andriy Shevchenko's side took the lead against the run of play in the 76th minute when Viktor Tsygankov took David de Gea by surprise by firing home from outside the area, after latching on to an outstanding reverse pass from Andriy Yarmolenko.
The goal was wildly celebrated by the whole Ukraine team with fans spaced out across the stadium, and the hosts taking advantage of UEFA regulations allowing supporters back at certain matches in an easing of coronavirus restrictions.
Ukraine had lost their last three outings, including a 4-0 reverse to Spain last month and a 7-1 thrashing at the hands of France in a friendly last week, after losing six players due to COVID-19 positives.
"I don't see myself as a hero. All our team are heroes," said match-winner Tsygankov.
The result shook up League A Group 4, giving Ukraine an outside chance of finishing top of the group with two games remaining.
"At the end of the game we entered into panic mode," said Spain coach Luis Enrique. "I've lost many games like this in my career, when you are playing better but the opponent grows in confidence then scores on the counterattack. But overall I liked what I saw from my players."
"I don't even need to say anything because my players have said everything with their attitude and commitment," Shevchenko told reporters.
"It's their victory, they were simply great. The guys have learned their lesson after the France game, they accepted the changes we suggested and fulfilled our plan.
"It was hard to compete with Spain but we fought all the time and we won lots of balls. We wanted to win and we won."
Luis Enrique's side took control of the play in the first half and practically monopolised possession, nearly going ahead with a Sergio Ramos free kick which struck the bar and when Ansu Fati caught clear sight of goal but missed the target.
Ukraine were much better after the break and Oleksandr Zubkov missed a golden chance to give them the lead when he deceived De Gea in the area but somehow missed the target with the goal gaping.
Spain then went for the jugular, as midfielder Rodri hit the post and Mikel Oyarzabal was thwarted by the outstanding Ukraine goalkeeper Georgiy Bushchan, who was making only his third appearance for his country after three other goalkeepers tested positive for the coronavirus.
Yet the visitors were soon undone down the other end by some lax goalkeeping from De Gea and were left to dwell on a shock defeat in the stadium where they had beaten Italy 4-0 in the Euro 2012 final.