Jude Bellingham's second half header meant City had been trailing with ten minutes left on the clock until John Stones' long range strike levelled the scores.
Pep Guardiola's side cranked up the pressure from there, eventually taking the lead in the 84th minute when Joao Cancelo's trivela cross dropped at the back post for Haaland to reach up and poke home against his old side.
Our manager likened the acrobatic finish to one he saw from the great Johan Cruyff. The Norwegian now has 26 goals in just 21 Champions League appearances, averaging a strike every 62 minutes on the pitch.
However, as the need for a comeback would suggest, we didn't have it all our own way on the night.
Here we'll take a look at the stats that told the story of the match...
We're used to seeing City peppering the opposition goal but that wasn't necessarily the case on Wednesday. Dortmund defended stoically for much of the night, with the ever impressive Mats Hummels able to anticipate our every move.
When you can't find another route to goal, it's worth trusting your high quality players with shots from distance. It may not be his usual game, but Stones' strike proves his attacking ability.
In fact, that was City's first shot on target on the night. We only managed another two strikes on goal, one of which was Haaland's winner and the other at the end of a burst of Julian Alvarez energy.
With three shots on target and an xG of just 0.97, according to FotMob, City were clinical even in the face of a defence who would not budge.
As the below graphic shows, it was a lengthy move even just to create the space for Stones' shot.
EBBS AND FLOWS
As the below graphic demonstrates, both sides had their own periods in control of the ball.
City had 66% of the ball but struggled to make inroads in the first half, with our most threatening period coming around the 35th minute mark.
Our visitors came out much the stronger of the two sides after the break, with Marco Reus missing a major chance even before Bellingham's goal.
However, City were on top from that moment on as we probed for the equaliser.
Three men that were important in changing that momentum after Bellingham's strike were the substitutes introduced in the 58th minute.
Julian Alvarez, Phil Foden and Bernardo Silva all came on together and provided a burst of energy that hemmed Dortmund in, eventually forcing the defenders back far enough to create the space for the shots and crosses that led to our goals.
As we can see from the Heat Maps below, Foden featured on the left wing, working closely with Bernardo who filled in the space behind him, while Alvarez played on the right but tended to drift inside at every opportunity.
In the end, the winning moment was all about one man again. Haaland showed an incredible level of athleticism to reach Cancelo's deep cross, lifting his leg almost to the height of Nico Schlotterbeck's head and maintaining the control to direct it goalwards.
He touched the ball 23 times in the match, the least of any starter in the City side. His four shots accrued an xG of just 0.3, meaning he turned low percentage chances into a goal, as he has done in his City career so far.
The Norwegian had been marshalled by Hummels and Niklas Sule prior to that, but that magical moment was enough to win the game and make Haaland the star of the show.
CHAMPIONS LEAGUE STATS SO FAR
- City's six goals so far is the second most of all 32 sides in the group stages, only behind Napoli (7)
- City have enjoyed 62% possession so far, the third most in the competition behind Chelsea and Barcelona
- Our passing accuracy of 90.5% is the second best in the competition, behind Real Madrid (91.5%)
- Erling Haaland has the joint most goals in the competition (3), alongside Kylian Mbappe and Robert Lewandowski
- Joao Cancelo's three assists so far are the most in the competition