Hahn (6-2) allowed one run as he improved to 4-0 in four road starts.
The Padres had 13 hits — 12 singles — to beat Alex Wood (7-8). Tommy Medica drove in a run and had a career-high four hits. Chris Denorfia had three hits and an RBI for San Diego.
The Padres, who were 5-1 against the Braves in 2013, have won five of their last six series against Atlanta since early in 2011.
The Braves fell 2 1/2 games behind first-place Washington in the NL East.
Wood allowed five runs, four earned. He gave up a career-high 12 hits, including three infield singles, in five innings.
The Braves scored one run in the eighth but left the bases loaded. Kevin Quackenbush gave up a two-out single to Freddie Freeman before walking Justin Upton.
Joaquin Benoit walked two batters, including a bases-loaded pass to Evan Gattis, to force in a run. Chris Johnson’s fly ball to shallow center field ended the inning.
Benoit had two strikeouts in a perfect ninth to earn his second save.
San Diego led 5-0 before Freeman hit a one-out triple off the wall in center field and scored on Upton’s sacrifice fly in the sixth.
Wood was helped by double plays in the first and second innings as he gave up eight hits but only two runs in the first three innings.
The Padres doubled their lead with two runs in the fourth. Denorfia had a run-scoring single and he scored on Yangervis Solarte’s fly ball for a 4-0 lead.
Rene Rivera added a run-scoring single off Wood in the fifth.
Padres manager Bud Black unsuccessfully challenged a call that Medica was forced out at second base in the fifth. Braves third baseman Chris Johnson bobbled Jeff Francoeur’s grounder before throwing to Tommy La Stella at second. The call stood following a review that lasted 3 minutes, 1 second.
At least one replay indicated Medica was safe. The verdict of insufficient clear and convincing evidence left Black shaking his head in the Padres’ dugout.
Francoeur, who played with his hometown Braves from 2005-09, received an ovation before his first at-bat. He was 0 for 3 with a walk.