The Russian side required victory to progress from Group G without relying on the outcome in the Spanish capital and Aleksandr Kerzhakov put them on course to do just that with the opener in the 35th minute.
However, Vienna scored three goals – two courtesy of Philipp Hosiner – within seven minutes either side of the break to leave Zenit facing an anxious wait before Roman Kienast added a fourth late.
Porto was unable to recover a first-half deficit, resigning it to Europa League football and sending Zenit through to the Champions League round of 16 with only six points from six games.
Vienna, which was guaranteed to finish bottom before kickoff, celebrated its first win in Europe's elite competition, with Tomas Jun also on target.
The home side was without defender Lukas Rotpuller and midfielder Bernhard Luxbacher because of injury, while playmaker Danny missed out for Zenit.
That did not prevent the Russian heavyweights from creating chances in an opening half hour they dominated.
Within 180 seconds, Hulk fired over the crossbar following a neat passing move. Domenico Criscito was then close to connecting with a Viktor Fayzulin cross, before Hulk created space for himself with some delightful footwork only to see his shot from the edge of the box blocked by Kaja Rogulj.
Zenit eventually broke the deadlock in the 35th minute. Kerzhakov's clever movement coupled with defender Manuel Ortlechner's untimely slip allowed the former to race on to Hulk's reverse through ball. Kerzhakov took it around goalkeeper Heinz Lindner and slotted home into the empty net.
Out of nothing, however, Vienna equalized on the stroke of halftime. Hosiner robbed Zenit of possession, played a superb one-two with Marko Stankovic and slotted the ball across goalkeeper Yuri Lodygin and into the bottom corner.
Within six minutes of the restart, Vienna was 3-1 up. First, following a very poor goal kick from Lodygin, Markus Suttner controlled the ball sublimely and crossed to give Jun a tap-in.
Then Florian Mader's long-range strike was parried by Lodygin straight into the path of Hosiner, who thumped the ball home to complete his double.
Zenit tried to respond as Konstantin Zyryanov went close from distance. Hulk forced Lindner into a smart save and Axel Witsel saw his powerful strike go narrowly over the crossbar.
But Vienna completed a 4-1 success in injury time, when the brilliant Hosiner crossed for substitute Kienast to fire home.
Follow GOAL.COM on Twitter