The midfielder accepted a pass from Ivo Pinto and cut in from the right to beat Frank Fielding with a sweetly struck left-footed shot from 15 yards.
The goal – Maddison’s eighth of the season – settled a closely fought game and condemned the hosts to a fifth straight defeat in all competitions.
Norwich made a bright start and forced the first save on 15 minutes when Fielding had to dive to his left to parry Maddison’s powerful shot from 25 yards.
The hosts responded quickly with Joe Bryan firing high and wide from distance following a corner routine off the training ground.
Liam Walsh, making his home debut for the hosts, almost gifted Norwich a 23rd-minute lead when caught in possession by Maddison. The midfielder fed Josh Murphy, whose shot from a narrow angle was brilliantly cleared off the line by Nathan Baker.
Bryan tried his luck again from 25 yards, but the shot was too close to Angus Gunn, who saved comfortably.
Korey Smith’s last-ditch tackle on Nelson Oliveira thwarted a dangerous Norwich break as the game opened up. With the visitors on top, Grant Hanley fired over from close range when the Robins failed to deal with a 35th-minute corner.
The Canaries were particularly dangerous on the break. Murphy fired over from the edge of the box after a swift counter-attack and the last action of the first half saw the visitors squander the best chance.
Oliveira broke away past Aden Flint and his low shot beat Fielding only to fizz inches wide, leaving the striker holding his head in frustration.
Bristol City piled on the pressure at the start of the second half, but the Norwich back-line held firm. Gunn had to make just one save, getting behind another stinging shot from Bryan as the hour mark approached.
There was a major scare for the visitors on 62 minutes when a left-wing corner from Walsh was played low into the path of Josh Brownhill, who hit the outside of a post with a brilliant 30-yard effort.
A foul by Walsh on Maddison 20 yards out then gave Norwich a chance, but the latter’s free-kick hit the defensive wall.
With the visitors still struggling to create clear openings, Lee Johnson gave a debut to winger Ryan Kent, on loan from Liverpool, in place of Walsh on 69 minutes.
His first contribution was to drive into the box and force a save from Gunn. A second substitution saw Matt Taylor replace Jamie Paterson.
Then came Maddison’s goal, the 21-year-old settling the contest 11 minutes from time with a fine strike.
Bristol City threw everything at Norwich in response and Gunn had to make a point-blank save from Brownhill during five minutes of stoppage time, but they could not muster an equaliser.
Brighton have been linked with a swoop on League One Sunderland for the signature of goalkeeper Jason Steele.
Southampton remain in the hunt for Red Bull Salzburg's Amadou Haidara and are reportedly readying a £15million offer.