Milan came into the clash looking for their first win of the season after losing 3-2 to Napoli last weekend, a game in which they led 2-0.
Hakan Calhanoglu returned to the Milan line-up after missing out through suspension last week, with Fabio Borini dropping to the bench.
Roma, meanwhile, handed a start start to new signing Steven Nzonzi, who joined the club from Sevilla in the off-season.
However, it was the hosts who looked more threatening in the opening stages of the half, although they struggled to carve out clear-cut openings.
Milan's dominance eventually paid off, with the home side taking the lead through Franck Kessie's close-range finish five minutes before the break.
The visitors looked livelier in the second stanza and they managed to level matters in the 59th minute with Federico Fazio's impressive first-time finish.
With 20 minutes remaining, the visitors opted to inject fresh legs as Bryan Cristante replaced off-season acquisition Javier Pastore.
Roma thought they had taken the lead in the 79th minute when N'Zonzi slotted home from a corner, but the Frenchman's strike was ruled out for a handball after consultation with the Video Assistant Referee (VAR).
The visitors did have a chance to secure victory in second-half stoppage time, but striker Edin Dzeko dragged his close-range effort wide of the upright.
Roma were made to rue that miss as Milan netted the winning goal in the final minutes of the game as Patrick Cutrone found the back of the net after a glorious pass from Gonzalo Higuain.