Riyad Mahrez saved a penalty but Manchester City still sealed top spot in their Champions League group with a draw that also sent Borussia Dortmund through to the last 16.
Mahrez was fouled by Emre Can and headed high, but Gregor Kobel got on the right path to save his shot.
Both sides knew that a draw would be enough to achieve their goals, so everyone will be happy with the result.
City boss Pep Guardiola surprisingly replaced top scorer Erling Haaland at half-time after he had just 13 touches, with Mats Hummels expertly tackling him in the middle.
Dortmund also had good chances, with 17-year-old Youssoufa Moukoko pulling wide and debutant City goalkeeper Stefan Ortega making several saves.
More to follow.
How to play
Rate all 10 players during or after the entire match. The evaluator will close 30 minutes after the final whistle.
Rating range key = Give it to me = Pure perfection
- 15HummelsBooked in 87 minutes
- 10T Riskreplaced byWolfin 82′minutes
- 27Adeyemireplaced bygrindingin 73′minutes
- 7Reynareplaced byPapadopoulosin 87′minutes
- 18from Moukoureplaced byhumblein 82′minutes
- 38without cutting
- 3Ruben Dias
- 7cancel itBooked in 7 minutesreplaced byAkanjiin 45′minutesBooked in 72 minutes
- 26Mahrezreplaced byPalmerin 88′minutes
- 8in GundoganBooked in 58 minutes
- 47the footreplaced byGrealishin 81′minutes
- 9Haalandreplaced byBernard Silvain 45′minutes
- 19AlvarezBooked in 31 minutes
- 17De Bruyne
- 20Bernard Silva
Game over, Borussia Dortmund 0, Manchester City 0.
The second half is over, Borussia Dortmund 0, Manchester City 0.
Offside, Borussia Dortmund. Julian Brandt tries to score, but Anthony Modeste is caught offside.
Dangerous play by Rúben Dias (Manchester City).
Jude Bellingham (Borussia Dortmund) wins a free kick.
Change, Manchester City. Cole Palmer replaces Riyad Mahrez.
Mats Hummels (Borussia Dortmund) is shown the yellow card for a bad foul.
Julián Álvarez (Manchester City) wins a free kick.
Foul by Mats Hummels (Borussia Dortmund).
Change, Borussia Dortmund. Antonios Papadopoulos replaces Giovanni Reyna.
Offside, Manchester City. Jack Grealish tries to score, but Bernardo Silva is offside.
Offside, Manchester City. John Stones tries a through ball, but Riyad Mahrez is caught offside.
Change, Borussia Dortmund. Anthony Modeste replaces Youssoufa Moukoko.
Change, Borussia Dortmund. Marius Wolfe replaces Thorgan Hazard.
Change, Manchester City. Jack Grealish has been replaced by Phil Foden.
Corner, Manchester City. Mats Hummels received the ball.
Attempt blocked. Thorgan Hazard (Borussia Dortmund) right footed shot from outside the box is saved in the center of the box.
Change, Borussia Dortmund. Donyell Malen replaces Karim Adeyemi.
Manuel Akanji (Manchester City) is shown a yellow card for handball.
Hand of Manuel Akanji (Manchester City).