Milan looked set to lose for the third time this season but a late flurry of goals secured a draw for the visitors.
Ignazio Abate scored a dramatic injury-time equalizer to deny the hosts their first win of the season, taking advantage of a defensive mix-up to fire home at the back post in the 92nd minute.
The visitors had looked dead and buried with just a minute of normal time left, but Brazilian forward Robinho swept home on 89 minutes to make it 3-2 and add to Andrea Poli’s first-half goal.
Bologna had stunned Milan by opening up a 3-1 lead in the second period with a double from Uruguayan midfielder Diego Laxalt and a header from Jonathan Cristaldo.
Milan coach Massimiliano Allegri was forced into a change in attack, with Robinho handed a rare start in place of leading scorer Mario Balotelli, suspended for three games following his post-match sending off in the home defeat to Napoli last week.
Stefano Pioli made wholesale changes for Bologna with six players recalled to the starting lineup, including defender Andrea Mantovani for the suspended Cesare Natali, who emulated Balotelli by both scoring and being dismissed in his team’s last outing, a 2-1 defeat to Torino.
Milan was dominant in possession from the outset and duly took the lead 12 minutes in, with midfielder Poli finishing across goalkeeper Gianluca Curci after being expertly played in by Robinho’s through ball.
The hosts’ first real chance did not arrive until the half-hour mark, when Alessandro Diamanti’s shot on the turn was beaten away by Milan goalkeeper Christian Abbiati.
But the home side did not have to wait long for an equalizer, as Laxalt beat the offside trap in the 33rd minute to fire home left-footed inside Abbiati’s near post.
Milan reacted well to Laxalt’s strike, and was only denied a halftime lead by Curci, who pulled off a brilliant double-save to block Robinho’s effort and Birsa’s follow-up.
Bologna came out with renewed impetus in the second half, and took the lead in the 52nd minute when Laxalt out-jumped Abate at the back post to head home a teasing cross from Greek winger Lazaros Christodoulopoulos.
The hosts then increased their advantage 10 minutes later, when Argentine striker Cristaldo glanced in Diamanti’s pinpoint feed from the left flank.
Milan continued to press, but it looked like Bologna would be able to hang on and claim the victory until Robinho bundled home after Curci had saved Sulley Muntari's initial effort.
And the draw was sealed by Abate’s late intervention as he too pounced on a rebound, after Curci had denied Robinho a hat trick.