The visitors had the chance to take the lead from the spot, but Niang erred and the Belgian took full advantage to keep his side four points behind Juventus.
M'Baye Niang's second penalty miss in as many matches proved costly for AC Milan as injury-hit Roma earned a 1-0 win over their Serie A title rivals thanks to Radja Nainggolan's stunning strike.
Nainggolan's individual brilliance put Luciano Spalletti's side ahead with just over an hour gone in a lacklustre encounter at Stadio Olimpico on Monday, but it came after Niang had squandered a gilt-edged chance in the first-half.
Niang fluffed his lines from the spot against Crotone last time out and the French forward could not better Wojciech Szczesny from 12 yards out on this occasion either.
Roma, without key players such as Francesco Totti and Mohamed Salah, did have the better of proceedings before the penalty incident, but failed to create any clear-cut opportunities, and were dealt a further blow when Bruno Peres picked up a seemingly serious injury before the interval.
But in spite of a rather tepid attacking display, Nainggolan's moment of inspiration proved to be the difference for the hosts, who move to within four points of Serie A leaders Juventus ahead of Saturday's top-of-the-table clash in Turin.
Vincenzo Montella, who spent 10 years at Roma as a player, must now lift his side for Saturday's home encounter with Atalanta.
Roma - fresh off beating rivals Lazio last time out - had lost just once in 11 Serie A home matches versus Milan before Monday's encounter and they started well with Edin Dzeko forcing Gianluigi Donnarumma into a superb save at his near post inside two minutes.
Milan weathered the storm, though, and the in-form Gianluca Lapadula just failed to latch onto Suso's cross.
Lapadula provided Milan with a great chance to go in front when he drew a clumsy foul from Szczesny in the 26th minute, but the goalkeeper atoned for his error by saving Niang's penalty low to his left.
That sparked Roman back into life and a brilliant strike from Dzeko went just wide of the upright.
Roma were dealt a blow before half-time, however, when - after a crunching challenge with Mattia De Sciglio - a distraught Peres was taken from the field on a stretcher to be replaced by former Milan star Stephan El Shaarawy, himself just back from injury.
Perhaps rocked by Peres' injury, Roma came out slowly at the restart, with Suso's dipping strike calling Szczesny into action.
Spalletti's men finally forged some meaningful ventures forward as the hour-mark approached - Nainggolan heading over before Diego Perotti hit the side-netting.
And Roma had their lead on 62 minutes when Nainggolan took matters into his own hands, the Belgian curling home a sumptuous finish from 30 yards following the culmination of a terrific run.
Milan did attempt to press for an equaliser late on – substitute Matias Fernandez striking straight at Szczesny from close-range – but that was all the visitors could muster as their five-match unbeaten streak in Serie A came to an end.