Sebastian Vettel finished second, while Charles Leclerc was back in fourth position.
Alexander Albon was fifth, Max Verstappen just behind and Sergo Perez to the delight of the crowd just behind him.
"Today's an incredible result, I just have to say an incredible thanks to my team," Hamilton said.
"We came here thinking we were on the back foot and it was a difficult race for us, but we pulled through.
"I had quite a bit of damage on my car so the race was quite a struggle.
"I don't mind [not winning the championship], I love racing and I just take it one race at a time. I've always wanted to win here."
Hamilton is now 74 points ahead of Bottas, so would only need to take a point in the next race in Austin, Texas to secure the championship or the Finn not win the race.
Leclerc is in third, just five points ahead of Vettel and 54 behind Bottas.
Starting third on the grid, Hamilton had a poor start, slipping to fifth position after colliding with Verstappen and falling behind Albon and Carlos Sainz but his team's one-stop strategy enabled him to stay in front and he took care of his tyres, saving enough to hold out in the closing stages.
The Brit was unsure about his team's decision earlier in the race, complaining that his team had gone too early on lap 23 with the tyre change but to his, and most onlookers' surprise, there was little wear on them in the closing stages and he comfortably held out.
Vettel stayed in the lead until the 37th lap, when Leclerc took over until his own, prolonged second stop on the 43rd lap which saw Albon in front briefly until his visit to the pits put Hamilton in front, an advantage he retained until the chequered flag where he clinched his first win in Mexico since 2016.