Sebastian Vettel held on in a grandstand finish as Bottas, on mediums to Vettel’s fading soft tyres, just failed to steal the victory.
Lewis Hamilton recovered from a grid penalty to complete the podium after Kimi Raikkonen’s hopes were dashed during a pitstop that left a Ferrari mechanic hurt and forced him to retire.
Vettel held the lead at the start as Bottas mugged Raikkonen into Turn 1, and Vettel built a lead of more than three seconds over the first stint.
Bottas began to claw back time and was just two seconds back when Ferrari brought the race leader in for a change of tyres.
Vettel switched to softs and Raikkonen pitted a lap later as Bottas continued for two more laps, with the Ferraris benefiting from the power of fresher rubber.
When Bottas finally stopped, taking on mediums, Vettel’s lead was north of eight seconds and Raikkonen had closed back in on the Mercedes.
The lead trio held station for several laps, only really disrupted when Vettel caught the longer-running Hamilton – who had risen from ninth – and had to wait to pass the Mercedes.
Raikkonen then made a second stop that threatened to inject a strategic variable into the lead fight but ended up removing him from the picture.
The Finn pulled away before the left-rear had been changed and struck a mechanic’s leg, while Raikkonen stopped in the pitlane with three new tyres and the unchanged old one on his car and retired.
On-track Vettel appeared to be preparing for a two-stop race but his commitment to a one-stop became clear as his pace held up and Bottas failed to make significant inroads.
The gap dipped below five seconds heading towards the final 10 laps, and suddenly Vettel’s lead began to quickly diminish.
Bottas entered DRS range with two laps to go but a half-hearted look at Turn 1 on the final lap was as close as he got.
Hamilton finished 8.5s adrift of the lead duo in third, with Red Bull the only missing ingredient after both its driver’s races imploded in the first couple of laps.
Max Verstappen squeezed Hamilton too hard exiting Turn 1 after passing him at the start of the second lap damaged his left-rear wheel, which caused a puncture.
He got back to the pits and had the tyres changed, but parked up shortly after with a differential problem.
Team-mate Daniel Ricciardo’s race ended shortly after Verstappen picked up a puncture when his car shut down exiting the Turn 8 hairpin.
Red Bull’s junior team afforded it reason to be cheerful though: Pierre Gasly was an incredible fourth place for Toro Rosso on only the team’s second start with Honda power.
Gasly kept clear of the squabbling Kevin Magnussen and Nico Hulkenberg, who clashed through Turn 2 over sixth on the opening lap but somehow escaped without damage, and was faultless for the remainder of the grand prix to bank his first points in F1 in style.
Magnussen then survived a near-miss with team-mate Romain Grosjean, who was out of sync on old tyres, at Turn 2 in the second half of the race to finish fifth.
Fernando Alonso leapt from 13th to ninth on the opening lap and drove a strong race after McLaren’s “astonishing” poor performance in qualifying.
He caught Hulkenberg’s Renault in the closing stages but had to settle for seventh, ahead of team-mate Stoffel Vandoorne who used medium tyres to good effect to climb to eighth after his second stop.
Sauber’s Marcus Ericsson banked his first points since the 2015 Italian Grand Prix in ninth place after running an extremely long first stint on softs and switching to mediums to execute a one-stop strategy to good effect.
Carlos Sainz Jr completed the points finishers in 10th.