Pep Guardiola’s side struggled to break down Palace until Haaland netted from the spot with 12 minutes left at rain-lashed Selhurst Park.
Haaland’s 34th goal in all competitions since joining from Borussia Dortmund last year was enough to seal City’s fifth win in their last six league games.
Having kept the pressure on Arsenal, the champions will hope Mikel Arteta’s men slip up when they travel to Fulham for their game in hand on Sunday.
City weren’t at their fluent best but the hard-fought victory was essential to stop Arsenal moving further into the distance in the title race.
Now Haaland and company will focus on the second leg of their Champions League last 16 clash against Leipzig in Manchester on Tuesday, with the tie delicately balanced at 1-1.
Palace are on the longest current winless run in the Premier League, failing to take maximum points from any of their 10 games in 2023, a dismal sequence that leaves them just four points above the relegation zone.
Guardiola left Kevin De Bruyne and Kyle Walker on the bench, the latter’s exile coming just days after police launched an investigation into allegations the England defender indecently exposed himself in a bar.
City made a strong start as Rodri’s powerful volley was parried by Palace keeper Vicente Guaita.
Ruben Dias’s attempt to turn in the rebound was blocked by Jeffrey Schlupp before Jack Grealish shot just wide moments later.
City were nearly caught out when Manuel Akanji was forced to race back to block Wilfried Zaha’s shot after Phil Foden carelessly surrendered possession.
– Haaland strikes –
Guardiola has claimed Foden is back to his best after a difficult season for the England playmaker.
But Foden struggled in the first half and Guardiola was on his feet barking at his star when his misplaced pass went straight to Palace’s Luka Milivojevic.
Haaland scored his first Premier League hat-trick against Palace in August as City came from two goals down at half-time to win 4-2.
Haaland should have put City ahead midway through the first half in the rematch, but he clipped over from six yards after Nathan Ake’s cross picked him out.
The Norway striker threatened again with a low cross-shot that Guaita blocked at the near post, with the rebound drilled wide by Haaland.
City maintained their territorial control in the second half and Jack Grealish quickly won a free-kick, from which Foden’s 25-yard strike drew a good save from Guaita.
Julian Alvarez, sent on in place of Foden, squandered a golden opportunity to break the deadlock as the Argentine World Cup winner blazed over after his nimble turn opened up the Palace defence.
Alvarez’s long-range effort was too close to Guaita soon afterwards, but City’s pressure was mounting and they struck in the 78th minute.
Michael Olise’s rash challenge on Ilkay Gundogan was ruled a penalty and Haaland stepped up to send Guaita the wrong way from the spot.
Haaland wasted a chance to kill off Palace when he headed over from Grealish’s cross.
That miss meant City had to survive a nervous finale, with Ederson saving from Eberechi Eze, before they could finally exhale.