Vettel remained ahead after the first round of pit stops but Mercedes' decision to pit Hamilton a second time under the Virtual Safety Car on lap 37 proved decisive.
Ferrari'sKimi Raikkonen and 2016 race victor Max Verstappen of Red Bull collided on the first turn, knocking both drivers out of the race.
Bottas' slight nudge of Raikkonen caused a chain-reaction, sending Raikkonen into Verstappen.
Vettel edged past the pole-sitting Hamilton at the first corner, but the British driver overtook Vettel's Ferrari with more than 20 laps left while running on a faster set of tires as Mercedes' pit strategy paid off.
Spain's double world champion Fernando Alonso, starting seventh for McLaren after a troubled practice, was forced into the gravel in a tussle with Williams's Felipe Massa and dropped to 13th. Vettel eventually got by on a third try, but by then Hamilton had pulled back some valuable seconds.
Verstappen's race was over just seconds after it began when his vehicle was on the receiving end of a knock between Valtteri Bottas' Mercedes and Kimi Raikkonen's Ferrari. But he would not have to wait long, the Mercedes driver blasting past on the straight a few laps later to take a lead he would not lose. Valtteri Bottas is third with 63 points, while Kimi Raikkonen holds the fourth place with 49 points.
Despite a great start in individual duels with Mercedes, Ferrari's top driver finished Sunday's Spanish Grand Prix exactly where he started: in second place behind Lewis Hamilton. It was a wheel-to-wheel competition between the two best drivers of their generation.
"I don't remember having a race like this for a long time where I was able to be on the limit as hard as I was and stay in a battle".
The virtual safety vehicle was deployed when Alonso's team mate Stoffel Vandoorne broke his car's suspension in a collision with Massa on lap 34.
"It could have been close, there could have been contact but fortunately I avoided it", Hamilton said.
"Lewis saved the race with an incredible drive", said Mercedes chairman Niki Lauda. "I just really have to congratulate and thank my team". His team mate Esteban Ocon finished fifth and Nico Hulkenberg from Renault has finished it in sixth spot.
"We tried to go for a one-stop race and I think it could have paid off without those two guys in front - Lewis (Hamilton) and Seb (Vettel)". The retirements of Raikonnen and Verstappen plus Hamilton's teammate Valtteri Bottas mean the championship is already looking like a two horse race.
On a bump with Vettel at turn one, he added: "I felt like I ran out of road, but was alongside".
"A lot of the races that we do with the type of racing that we sometimes have to do, where you're saving fuel, like in the last race for example [in Russia], I couldn't push because the auto was overheating".