Mattia Destro opened the scoring for Roma in the 13th minute with his second goal in as many matches but Cristian Zapata leveled on the half-hour mark.
Kevin Strootman restored Roma’s lead in the 52nd minute from the penalty spot after substitute goalkeeper Gabriel had needlessly fouled Gervinho.
Tensions began to fray at San Siro and Milan coach Massimiliano Allegri was sent to the stands, while captain Riccardo Montolivo was booked for dissent and will miss Sunday’s derby match against Inter Milan.
Sulley Muntari rescued a point for Milan 13 minutes from time. It was the first time Roma – which has the stingiest defense in Serie A – had let in two goals in a match all season.
Roma remained second but is five points behind Juventus.
There was good news for the capital side, however, as talismanic captain Francesco Totti made his long-awaited return after more than two months out with a hamstring injury. The forward replaced Destro in the 64th minute.
Milan’s injury woes grew. Already without Stephan El Shaarawy, Valter Birsa, Ignazio Abate, Robinho, Kevin Constant, Matias Silvestre and Marco Amelia before kickoff, goalkeeper Cristian Abbiati and Emanuelson had to be replaced during the match.
Milan was celebrating its 114th birthday and before the match the Curva Sud unfurled a banner honoring its founder Herbert Kilpin.
Allegri’s side was the only Italian team to make it through to the knockout stage of the Champions League but was languishing in mid-table after just one win in its past seven matches.
Roma had topped the table for most of the start of the season but had only recently got back to winning ways, with a 2-1 victory over Fiorentina snapping a run of four successive draws.
The visiting side had the first chance of the match in the seventh minute when Gervinho cut in from the left but his shot from a tight angle was easily saved at the near post by Abbiati.
Roma took the lead six minutes later when Strootman rolled the ball across the area for Destro to slide in and fire home. The forward had scored last week on his comeback from several months out with injury.
Kaka went close to leveling for Milan in the 20th but his effort flew narrowly past the right upright.
Roma almost gifted Milan the equalizer following a poor clearance from Napoli goalkeeper Morgan De Sanctis, who was surprised by a back pass from Dodo. Emanuelson mazed his way into the area but his angled drive was deflected over the bar.
However, Muntari nodded the resulting corner on to Zapata, who headed it down and in over the line.
Roma thought it had restored its advantage moments later but Daniele Bonera made a goalline clearance to deny Michael Bradley, with the ball millimeters from going over.
In a frantic few minutes at San Siro, Zapata also denied Gervinho a clear-cut opportunity with a perfectly-timed last-ditch tackle.
Gabriel replaced Abbiati at the break and gave away a penalty sevent minutes later when he came rushing out and scythed down Gervinho.
Strootman stepped up and fired into the bottom right corner.
Milan had a strong penalty claim of its own turned down five minutes later when Mario Balotelli appeared to be pushed over in the area by Mehdi Benatia but the referee awarded a free kick against the Milan forward.
The home side had a stronger appeal turned down in the 68th minute when Dodo seemed to shove Kaka.
However, Milan was back on level terms shortly afterward when Balotelli controlled the ball well under pressure and managed to pass to Muntari, who slotted it into the bottom near corner.
Both sides had chances to win the match in stoppage time with Balotelli firing wide after doing well to dummy Daniele De Rossi and create space for himself. Gervinho also missed the target with the last kick of the match.