Wilfried Zaha became the first player to score 50 top-flight goals for Crystal Palace as 10-man Manchester City suffered a shock defeat at Etihad Stadium.
Zaha struck after just six minutes when Conor Gallagher robbed Aymeric Laporte inside his own half before Gallagher wrapped up the points when he fired home two minutes from time.
Laporte was red-carded by referee Andre Marriner in first-half stoppage time when he committed a professional foul by bringing down Zaha 35 yards from the City goal.
Even a man down, the hosts remained a goal threat and Gabriel Jesus thought he had levelled when he turned home Phil Foden's superb far-post cross, only for video assistant referee Lee Mason to rule the England forward was offside in the build-up.
City fans were infuriated by what they saw as time-wasting from Palace, which started in the opening period, and manager Pep Guardiola - marking his 200th match in the Premier League as a manager - was less than impressed with what he saw too, judging by the number of times he spoke to fourth official Anthony Taylor.
But Palace were a danger on the break, with Jordan Ayew and Gallagher both wasting decent chances before Gallagher finished Michael Olise's lay-off to give Patrick Vieira's men victory and end a frustrating run of four consecutive Premier League draws.
- Follow reaction from Man City v Palace plus live text commentary of Saturday's Premier League games
- Go straight to all the best City content
- Visit the Palace page
Man City defending falls short
City's defence had been virtually watertight this season but there was an element of over-confidence that led to Palace's breakthrough.
Laporte had lots of space and time to decide what to do with the ball as he advanced towards the halfway line. But he didn't react as Gallagher closed in and a quick exchange of passes later, Zaha was through.
The contact wasn't the greatest but the accuracy was there and the shot found the bottom corner.
It was the first Premier League goal City had conceded at home all season and only their fourth in the top flight in total.
Laporte's dismissal made their task harder and Bernardo Silva and Jesus both needed to be calmed down as the half-time whistle blew, even though the Spain defender's only complaint could be the distance from his own goal that the offence took place.
Although Palace memorably won at this ground in December 2018, it was their only positive result in 12 trips to Etihad Stadium that otherwise yielded just two points.
For Vieira, victory was particularly special, partly because of the time he spent at City as both a player and a youth-team coach, but mainly because of the nasty habit his side had developed of giving away leads late in games.
Zaha's goal was the fourth time in five matches they had been in front - yet they had failed to win any of the previous three.
Yet again, Gallagher was superb in midfield, his energy helping to shield a defence who, at times, did exceptionally well not to be lured into giving away a penalty, in particular by the close control of Bernardo and Jack Grealish.
By the time Gallagher scored, Palace had weathered the storm as City slipped five points behind leaders Chelsea.
Manchester City are next in action against Belgian side Club Bruges in the Champions League on Wednesday, 3 November (20:00 GMT). Their next Premier League game is at Manchester United on Saturday, 6 November (12:30).
Crystal Palace's next game is against Wolves at Selhurst Park, also on 6 November (15:00).
Player of the match
with an average of 9.40
Squad number47Player nameFoden
Squad number20Player nameBernardo Silva
Squad number17Player nameDe Bruyne
Squad number9Player nameGabriel Jesus
Squad number31Player nameEderson
Squad number3Player nameRúben Dias
Squad number5Player nameStones
Squad number2Player nameWalker
Squad number10Player nameGrealish
Squad number16Player nameRodri
Squad number27Player nameJoão Cancelo
Squad number14Player nameLaporte
Squad number26Player nameMahrez
Squad number7Player nameSterling
Squad number13Player nameGuaita
Squad number11Player nameZaha
Squad number23Player nameGallagher
Squad number7Player nameOlise
Squad number22Player nameÉdouard
Squad number18Player nameMcArthur
Squad number3Player nameMitchell
Squad number8Player nameKouyaté
Squad number6Player nameGuéhi
Squad number16Player nameAndersen
Squad number2Player nameWard
Squad number9Player nameJ Ayew
Squad number15Player nameSchlupp
Squad number20Player nameBenteke
- 31EdersonBooked at 45mins
- 3Rúben Dias
- 14LaporteBooked at 45mins
- 27CanceloSubstituted forMahrezat 78'minutes
- 17De BruyneSubstituted forStonesat 59'minutes
- 20Bernardo SilvaBooked at 45mins
- 9Gabriel Jesus
- 10GrealishSubstituted forSterlingat 78'minutes
- 13GuaitaBooked at 86mins
- 23GallagherBooked at 65mins
- 8KouyatéSubstituted forOliseat 85'minutes
- 9J AyewBooked at 27minsSubstituted forBentekeat 65'minutes
- 22ÉdouardSubstituted forSchluppat 73'minutes
Match ends, Manchester City 0, Crystal Palace 2.
Second Half ends, Manchester City 0, Crystal Palace 2.
Attempt missed. Riyad Mahrez (Manchester City) header from the centre of the box is close, but misses to the left. Assisted by Raheem Sterling with a cross.
Hand ball by Conor Gallagher (Crystal Palace).
John Stones (Manchester City) wins a free kick in the defensive half.
Foul by Joel Ward (Crystal Palace).
Offside, Crystal Palace. Michael Olise tries a through ball, but Wilfried Zaha is caught offside.
Foul by Raheem Sterling (Manchester City).
Wilfried Zaha (Crystal Palace) wins a free kick in the defensive half.
Rúben Dias (Manchester City) wins a free kick in the defensive half.
Foul by Michael Olise (Crystal Palace).
Goal! Manchester City 0, Crystal Palace 2. Conor Gallagher (Crystal Palace) right footed shot from the centre of the box to the top right corner. Assisted by Michael Olise.
Vicente Guaita (Crystal Palace) is shown the yellow card.
Substitution, Crystal Palace. Michael Olise replaces Cheikhou Kouyaté because of an injury.
Attempt blocked. Christian Benteke (Crystal Palace) right footed shot from outside the box is blocked. Assisted by James McArthur.
Substitution, Manchester City. Raheem Sterling replaces Jack Grealish.
Substitution, Manchester City. Riyad Mahrez replaces João Cancelo.
Attempt missed. Jeffrey Schlupp (Crystal Palace) header from the right side of the box is too high. Assisted by Conor Gallagher with a cross following a corner.
Corner, Crystal Palace. Conceded by Ederson.
Attempt saved. Conor Gallagher (Crystal Palace) right footed shot from the right side of the box is saved in the bottom right corner. Assisted by Wilfried Zaha.
- Our coverage of your Premier League club is bigger and better than ever before - follow your team and sign up for notifications in the BBC Sport app to make sure you never miss a moment