The Portuguese champions took a surprise early lead but Sergio Aguero quickly levelled from the spot and second-half goals from Ilkay Gundogan and substitute Ferran Torres gave City victory.
This was not a vintage performance from Pep Guardiola’s side, who were sloppy at the back especially early on, but they were in full control by the time their opening game in Group C was over.
City had not even managed a shot at goal when they fell behind in the 14th minute, after a poor pass by Ruben Dias allowed Matheus Uribe to start a Porto attack.
Uribe found Colombian forward Luis Diaz, who was allowed to cut inside from the left and run virtually unchallenged into the City box before beating Ederson with a low shot.
City were not behind for long, however, with Aguero given the chance to equalise from the spot after Gundogan hit the post and Pepe clumsily took out Raheem Sterling as he chased the rebound.
Porto were unhappy with the decision, claiming Gundogan had stepped on goalkeeper Agustin Marchesin in the build-up, but the penalty stood and Aguero blasted home his 40th Champions League goal.
There were further chances for the visitors before the break, with Kyle Walker having to clear Sergio Oliveira’s shot off the line.
But they were much less of a threat in the second half, which was when City began to exert some authority in midfield.
The chances were hardly flowing for Guardiola’s men either, but Gundogan showed a touch of class to bend in his free-kick over the wall from the edge of the area and give his side the lead.
By now City were on top and Torres made certain of victory seconds after replacing Aguero, playing a neat one-two with fellow substitute Phil Foden and curling his shot home.
Aguero ends goal drought
It is only 67 days since City’s defeat against Lyon in the delayed quarter-finals of last year’s competition, and that disappointment must be fresh in Guardiola’s mind.
His side made a sluggish start here too, but in the end he will have seen plenty to improve his mood – notably the end of Aguero’s goal drought.
The prolific Argentina striker had gone 230 days without scoring before converting his penalty, the longest spell of his illustrious career.
Aguero had missed a large portion of that spell through injury, before making a return to action against Arsenal last weekend.
His fitness and form is surely key to City success, especially with their only other senior striker Gabriel Jesus sidelined, and it must be reassuring for Guardiola to see him back among the goals.
The bad news for City? Another injury
The only cloud for City was to see another player – substitute Fernandinho – injured and forced off himself before the end.
Fernandinho had been a particularly vocal supporter of his side from the stands during the first half but they will not want him to have to stay there for a long period.
With a busy schedule ahead, they are already without their talisman Kevin de Bruyne as well as Jesus, Nathan Ake and Aymeric Laporte.
Uefa regulations allow clubs to name 12 substitutes for each Champions League game, but it was telling that City had two keepers – Zack Steffen and Scott Carson – on their bench.
What’s next? A trip to France
City head for the south of France next Tuesday, 27 October, to play Marseille in their second game in Group C, at the same time as Porto entertain Olympiakos (both 20:00 GMT kick-offs).
Before then, Guardiola’s side travel to London to face West Ham in the Premier League on Saturday (12:30).