Nicola Legrottaglie headed the visitors in front on the half-hour mark, only for Mathieu Flamini to equalise on the stroke of half-time.
Gonzalo Bergessio restored the Sicilians' lead on 65 minutes, but two goals in four minutes from substitute Giampaolo Pazzini turned the game in the Rossoneri's favour before a late Mario Balotelli penalty sealed matters.
With Fiorentina winning earlier on Sunday, Milan knew only a victory would keep them in a Champions League qualifying spot.
They suffered a setback in the 30th minute, though, when Catania took the lead, Legrottaglie flicking Francesco Lodi's free-kick into the top-right corner.
The goal clearly rattled Milan, who laid siege to the visitors' goal.
Catania goalkeeper Alberto Frison got his fingertips to a powerful Kevin-Prince Boateng half-volley to turn the ball onto the crossbar before saving from Antonio Nocerino moments later.
Balotelli and Boateng both had shots blocked as the ball cannoned threateningly around the Catania penalty area before Frison turned Balotelli's free-kick behind.
The visitors' resistance was finally broken on the stroke of half-time, and Frison could not do anything to prevent it as Flamini swept Boateng's headed pass into the far corner.
Catania regained the lead in the 65th minute when Bergessio was put through by a fine Pablo Barrientos pass, and he lifted the ball in over the onrushing Marco Amelia.
Their lead lasted less than 10 minutes, though, before the first mistake of the night by Frison was punished with Pazzini on hand to tuck the ball in off the inside of the post after Balotelli's shot had been fumbled.
Just three minutes later, another save from Frison fell to Pazzini, who put Milan ahead.
Ballotelli wrapped things up from the penalty spot in stoppage time as Milan regained third spot and severely dented any remaining hopes Catania had of qualifying for Europe themselves.