The Astros entered the game having taken four of the previous six against the A's after losing the first 10 meetings of the season, but Oakland used the win to take a half-game lead in the American League West.
Dallas Keuchel lasted 3 1/3 innings for the Astros, yielding five runs off 10 hits and two walks. He was spotted with the lead after Houston's three-run third inning, but it wouldn't last. The two teams exchanged the lead five times before Donaldson clubbed his 21st dinger of the season.
The third inning began with a double by Jonathan Villar and singles from Jose Altuve and Trevor Crowe. Matt Dominguez, playing in his first game since Monday after missing time with a sinus infection, then singled in two runs to take a 3-1 lead.
Villar -- who went 3-for-5 -- gave the Astros another lead in the fourth with a bunt single toward first base that scored Brett Wallace from third.
The A's soon bounced back, scoring two runs in the fourth and sixth innings. They received 13 hits from eight members of their starting lineup, compared to Houston's six starters combining for 11 hits.
"We had a good game plan going in," Keuchel said. "I felt like the slider was keeping them in check early in the count because they like to hack. Some of those base hits were just because they're strong enough to get them through the hole. It's just one of those days where nothing was going right and everything was going wrong."
Keuchel had lasted at least seven innings in four of his previous five starts dating back to July 27. The extended at-bats, combined with what he considered to be a tight strike zone from home-plate umpire Alan Porter, contributed to his falling to 1-3 with a 5.51 ERA over his past six starts.
"I don't really say too much to the umpires, but I felt like a few of those inside fastballs were right there in the zone," Keuchel said. "It looked like he had a pretty decent zone, and it's just one of the frustrating parts. I can't live on the outside part of the plate all day long. I was getting them to chase the slider early and trying to back it up late with the fastball inside and I just wasn't getting the call."
Keuchel wasn't the only Astros player frustrated with Porter's officiating. Brandon Barnes was tossed in the sixth after arguing with Porter after he was hit by a pitch from A's right-hander A.J. Griffin but denied first base.
Porter ruled that Barnes, who leads Houston with seven hit-by-pitches this season, didn't make enough of an effort to avoid the pitch. Barnes eventually struck out swinging.
"He told me I leaned over and I leaned into it," Barnes said. "That's a judgment call. So I went back to the dugout."
Barnes disputed the call at the plate and continued to express his anger over the call from the dugout and eventually was ejected.
"I was at the bat rack and I was yelling at the bat rack, and I guess he heard something," he said. "I wasn't deliberately yelling at him. Again, it's a judgment call."
The Astros responded by threatening in the eighth with runners on the corners with two outs, but L.J. Hoes struck out looking on a 95-mph fastball from Ryan Cook to end the inning.
They pushed a run across in the ninth against A's closer Grant Balfour on a fielding error by second baseman Eric Sogard before the rally fell short.
"They battled all the way until the end," Astros manager Bo Porter said. "It was good to see. Really good at-bats during the ninth. They made him throw a bunch of pitches, and they definitely had to earn it."